diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,19 @@
 # Changelog for the Clash project
+## 1.4.7 *Jan 30th 2022*
+Fixed:
+  * Clash now shows days in time strings for compile runs which take longer than a day [#1989](https://github.com/clash-lang/clash-compiler/compare/issue-1989).
+  * Types defined in the package head are no longer qualified in the package body when rendering VHDL [#1996](https://github.com/clash-lang/clash-compiler/issues/1996).
+  * `asyncRam` with different read and write clocks no longer produce the wrong results in Haskell simulation. [#2031](https://github.com/clash-lang/clash-compiler/pull/2031)
+  * `Clash.Explicit.RAM.asyncRam#` Haskell simulation incorrectly treated an _undefined_ write enable as asserted. It now causes an _undefined_ value to be written instead. This problem did not propagate to the other `asyncRam` functions, where the same condition would simultaneously lead to an undefined write address, which would be handled correctly. This problem also only affects Haskell simulation, not the generated HDL. [#2031](https://github.com/clash-lang/clash-compiler/pull/2031)
+  * `Clash.Explicit.BlockRam.blockRam#` and `Clash.Explicit.BlockRam.File.blockRamFile#` Haskell simulation incorrectly treated an _undefined_ write enable as asserted. It now causes an _undefined_ value to be written instead. This problem did not propagate to the other `blockRam` functions, where the same condition would simultaneously lead to an undefined write address, which would be handled correctly. This problem also only affects Haskell simulation, not the generated HDL.([#2054](https://github.com/clash-lang/clash-compiler/pull/2054))
+
+Internal changes:
+  * Removed instances of `Hashable Term` and `Hashable Type` [#1986](https://github.com/clash-lang/clash-compiler/pull/1986)
+  * Added structural equality on `Term` (`Clash.Core.Subst.eqTerm`) and `Type` (`Clash.Core.Subst.eqType`)
+
+Internal fixes:
+  * Enable used to be a `Bool` in the Blackbox DSL, so we could use `boolToBit`. However it now has its own type in the DSL (`Enable domainName`), so we've added a new conversion function in order to convert it to a Bool.
+
 
 ## 1.4.6 *Oct 26th 2021*
 
diff --git a/clash-prelude.cabal b/clash-prelude.cabal
--- a/clash-prelude.cabal
+++ b/clash-prelude.cabal
@@ -1,6 +1,6 @@
 Cabal-version:        2.2
 Name:                 clash-prelude
-Version:              1.4.6
+Version:              1.4.7
 Synopsis:             Clash: a functional hardware description language - Prelude library
 Description:
   Clash is a functional hardware description language that borrows both its
@@ -50,7 +50,8 @@
 Maintainer:           QBayLogic B.V. <devops@qbaylogic.com>
 Copyright:            Copyright © 2013-2016, University of Twente,
                                   2016-2017, Myrtle Software Ltd,
-                                  2017-2019, QBayLogic B.V., Google Inc.
+                                  2017-2019, QBayLogic B.V., Google Inc.,
+                                  2020-2022, QBayLogic B.V.
 Category:             Hardware
 Build-type:           Custom
 
@@ -318,11 +319,12 @@
                       data-binary-ieee754       >= 0.4.4   && < 0.6,
                       data-default-class        >= 0.1.2   && < 0.2,
                       deepseq                   >= 1.4.1.0 && < 1.5,
+                      extra                     >= 1.6.17  && < 1.8,
                       ghc-prim                  >= 0.5.1.0 && < 0.8,
                       ghc-typelits-extra        >= 0.4     && < 0.5,
                       ghc-typelits-knownnat     >= 0.7.2   && < 0.8,
                       ghc-typelits-natnormalise >= 0.7.2   && < 0.8,
-                      hashable                  >= 1.2.1.0  && < 1.4,
+                      hashable                  >= 1.2.1.0  && < 1.5,
                       half                      >= 0.2.2.3 && < 1.0,
                       interpolate               >= 0.2     && < 0.3,
                       lens                      >= 4.10    && < 5.1.0,
@@ -334,16 +336,16 @@
                       th-abstraction            >= 0.2.10 && < 0.5.0,
                       th-lift                   >= 0.7.0    && < 0.9,
                       th-orphans                >= 0.13.1   && < 1.0,
-                      text                      >= 0.11.3.1 && < 1.3,
+                      text                      >= 0.11.3.1 && < 2.1,
                       text-show                 >= 3.7     && < 3.10,
-                      time                      >= 1.8     && < 1.13,
+                      time                      >= 1.8     && < 1.14,
                       transformers              >= 0.5.2.0 && < 0.7,
                       type-errors               >= 0.2.0.0 && < 0.3,
                       uniplate                  >= 1.6.12  && < 1.7,
                       vector                    >= 0.11    && < 1.0
 
   if impl(ghc >= 9.0.0)
-    Build-Depends:    ghc-bignum                >= 1.0      && < 1.1
+    Build-Depends:    ghc-bignum                >= 1.0      && < 1.3
   else
     Build-Depends:    integer-gmp               >= 1.0.1.0  && < 2.0
   if flag(large-tuples)
@@ -402,11 +404,13 @@
                  Clash.Tests.AutoReg
                  Clash.Tests.BitPack
                  Clash.Tests.BitVector
+                 Clash.Tests.BlockRam
                  Clash.Tests.DerivingDataRepr
                  Clash.Tests.DerivingDataReprTypes
                  Clash.Tests.Fixed
                  Clash.Tests.FixedExhaustive
                  Clash.Tests.NFDataX
+                 Clash.Tests.Ram
                  Clash.Tests.Reset
                  Clash.Tests.Resize
                  Clash.Tests.Signal
diff --git a/src/Clash/Annotations/Primitive.hs b/src/Clash/Annotations/Primitive.hs
--- a/src/Clash/Annotations/Primitive.hs
+++ b/src/Clash/Annotations/Primitive.hs
@@ -272,7 +272,7 @@
   -- ^ Description of a primitive for a given 'HDL's in a file at 'FilePath'
   | InlinePrimitive [HDL] String
   -- ^ Description of a primitive for a given 'HDL's as an inline 'String'
-  deriving (Show, Read, Data, Generic, NFData, Hashable)
+  deriving (Show, Read, Data, Generic, NFData, Hashable, Eq)
 
 -- | Primitive guard to mark a value as either not translatable or as having a
 -- blackbox with an optional extra warning. Helps Clash generate better error
@@ -287,7 +287,9 @@
   | HasBlackBox [PrimitiveWarning] a
   -- ^ Marks a value as having a blackbox. Clash will error if it hasn't found
   -- a blackbox.
-    deriving (Show, Read, Data, Generic, NFData, Hashable, Functor, Foldable, Traversable, Binary)
+  deriving
+    ( Show, Read, Data, Generic, NFData, Hashable, Functor, Foldable
+    , Traversable, Binary, Eq )
 
 -- | Warning that will be emitted on instantiating a guarded value.
 data PrimitiveWarning
@@ -296,7 +298,7 @@
   -- instantiated in a non-testbench context.
   | WarnAlways String
   -- ^ Always emit warning upon primitive instantiation.
-    deriving (Show, Read, Data, Generic, NFData, Hashable, Binary)
+    deriving (Show, Read, Data, Generic, NFData, Hashable, Binary, Eq)
 
 -- | Extract primitive definition from a PrimitiveGuard. Will yield Nothing
 -- for guards of value 'DontTranslate'.
diff --git a/src/Clash/Examples/Internal.hs b/src/Clash/Examples/Internal.hs
--- a/src/Clash/Examples/Internal.hs
+++ b/src/Clash/Examples/Internal.hs
@@ -105,7 +105,7 @@
     s = register 0 (mux upDown (s + 1) (s - 1))
 
 lfsrF' :: BitVector 16 -> BitVector 16
-lfsrF' s = pack feedback ++# slice d15 d1 s
+lfsrF' s = pack feedback ++# slice (SNat @15) d1 s
   where
     feedback = s!5 `xor` s!3 `xor` s!2 `xor` s!0
 
diff --git a/src/Clash/Explicit/BlockRam.hs b/src/Clash/Explicit/BlockRam.hs
--- a/src/Clash/Explicit/BlockRam.hs
+++ b/src/Clash/Explicit/BlockRam.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2013-2016, University of Twente,
                   2016-2017, Myrtle Software Ltd,
-                  2017     , Google Inc.
+                  2017     , Google Inc.,
+                  2021-2022, QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 BlockRAM primitives
 
@@ -234,7 +235,7 @@
 'Clash.Prelude.RAM.asyncRam' is /undefined/, and consequently, the first few
 output samples are also /undefined/. We use the utility function
 'Clash.XException.printX' to conveniently filter out the undefinedness and
-replace it with the string "X" in the few leading outputs.
+replace it with the string @\"undefined\"@ in the first few leading outputs.
 
 @
 >>> printX $ sampleN 32 $ system2 prog systemClockGen resetGen enableGen
@@ -364,7 +365,7 @@
 When we simulate our system we see that it works. This time again,
 we need to disregard the first sample, because the initial output of a
 'blockRam' is /undefined/. We use the utility function 'Clash.XException.printX'
-to conveniently filter out the undefinedness and replace it with the string "X".
+to conveniently filter out the undefinedness and replace it with the string @\"undefined\"@.
 
 @
 >>> printX $ sampleN 34 $ system3 prog2 systemClockGen resetGen enableGen
@@ -695,7 +696,8 @@
 -- | Create a blockRAM with space for @n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is /undefined/
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- @
 -- bram40
@@ -741,7 +743,8 @@
 -- | Create a blockRAM with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is /undefined/
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- @
 -- bram32
@@ -768,9 +771,7 @@
   -> Enable dom
   -- ^ Global enable
   -> Vec (2^n) a
-  -- ^ Initial content of the BRAM, also
-  -- determines the size, @2^n@, of
-  -- the BRAM.
+  -- ^ Initial content of the BRAM
   --
   -- __NB__: __MUST__ be a constant.
   -> Signal dom (Unsigned n)
@@ -788,7 +789,7 @@
   ClearOnReset :: ResetStrategy 'True
   NoClearOnReset :: ResetStrategy 'False
 
--- | Version of blockram that has no default values set. May be cleared to a
+-- | Version of blockram that has no default values set. May be cleared to an
 -- arbitrary state using a reset function.
 blockRamU
    :: forall n dom a r addr
@@ -811,7 +812,7 @@
   -> SNat n
   -- ^ Number of elements in BRAM
   -> (Index n -> a)
-  -- ^ If applicable (see first argument), reset BRAM using this function.
+  -- ^ If applicable (see 'ResetStrategy' argument), reset BRAM using this function.
   -> Signal dom addr
   -- ^ Read address @r@
   -> Signal dom (Maybe (addr, a))
@@ -1006,10 +1007,16 @@
 
   upd ram we waddr d = case maybeIsX we of
     Nothing -> case maybeIsX waddr of
-      Nothing -> fmap (const (seq waddr d)) ram
-      Just wa -> Seq.update wa d ram
+      Nothing -> -- Put the XException from `waddr` as the value in all
+                 -- locations of `ram`.
+                 seq waddr d <$ ram
+      Just wa -> -- Put the XException from `we` as the value at address
+                 -- `waddr`.
+                 Seq.update wa (seq we d) ram
     Just True -> case maybeIsX waddr of
-      Nothing -> fmap (const (seq waddr d)) ram
+      Nothing -> -- Put the XException from `waddr` as the value in all
+                 -- locations of `ram`.
+                 seq waddr d <$ ram
       Just wa -> Seq.update wa d ram
     _ -> ram
 {-# ANN blockRam# hasBlackBox #-}
diff --git a/src/Clash/Explicit/BlockRam/File.hs b/src/Clash/Explicit/BlockRam/File.hs
--- a/src/Clash/Explicit/BlockRam/File.hs
+++ b/src/Clash/Explicit/BlockRam/File.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017     , Google Inc.
-                  2019     , Myrtle Software Ltd
+                  2019     , Myrtle Software Ltd,
+                  2021-2022, QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 = Initializing a BlockRAM with a data file #usingramfiles#
 
@@ -113,7 +114,8 @@
 -- | Create a blockRAM with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
@@ -158,7 +160,8 @@
 -- | Create a blockRAM with space for @n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
@@ -252,10 +255,16 @@
 
     upd ram we waddr d = case maybeIsX we of
       Nothing -> case maybeIsX waddr of
-        Nothing -> fmap (const (seq waddr d)) ram
-        Just wa -> Seq.update wa d ram
+        Nothing -> -- Put the XException from `waddr` as the value in all
+                   -- locations of `ram`.
+                   seq waddr d <$ ram
+        Just wa -> -- Put the XException from `we` as the value at address
+                   -- `waddr`.
+                   Seq.update wa (seq we d) ram
       Just True -> case maybeIsX waddr of
-        Nothing -> fmap (const (seq waddr d)) ram
+        Nothing -> -- Put the XException from `waddr` as the value in all
+                   -- locations of `ram`.
+                   seq waddr d <$ ram
         Just wa -> Seq.update wa d ram
       _ -> ram
 
diff --git a/src/Clash/Explicit/RAM.hs b/src/Clash/Explicit/RAM.hs
--- a/src/Clash/Explicit/RAM.hs
+++ b/src/Clash/Explicit/RAM.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017     , Google Inc.
-                  2019     , Myrtle Software Ltd
+                  2019     , Myrtle Software Ltd,
+                  2022     , QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 RAM primitives with a combinational read port.
 -}
@@ -34,16 +35,17 @@
 import GHC.TypeLits          (KnownNat)
 import qualified Data.Sequence as Seq
 
-import Clash.Explicit.Signal
-  (unbundle, unsafeSynchronizer, KnownDomain, enable)
+import Clash.Explicit.Signal (unbundle, KnownDomain, enable)
 import Clash.Promoted.Nat    (SNat (..), snatToNum, pow2SNat)
 import Clash.Signal.Internal (Clock (..), Signal (..), Enable, fromEnable)
+import Clash.Signal.Internal.Ambiguous (clockPeriod)
 import Clash.Sized.Unsigned  (Unsigned)
-import Clash.XException      (errorX, maybeIsX, fromJustX)
+import Clash.XException      (errorX, maybeIsX, fromJustX, seqX)
 
 -- | Create a RAM with space for 2^@n@ elements
 --
--- * __NB__: Initial content of the RAM is 'undefined'
+-- * __NB__: Initial content of the RAM is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
@@ -75,7 +77,8 @@
 
 -- | Create a RAM with space for @n@ elements
 --
--- * __NB__: Initial content of the RAM is 'undefined'
+-- * __NB__: Initial content of the RAM is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
@@ -110,7 +113,8 @@
 
 -- | RAM primitive
 asyncRam#
-  :: ( HasCallStack
+  :: forall wdom rdom n a
+   . ( HasCallStack
      , KnownDomain wdom
      , KnownDomain rdom )
   => Clock wdom
@@ -131,29 +135,56 @@
   -- ^ Value to write (at address @w@)
   -> Signal rdom a
   -- ^ Value of the @RAM@ at address @r@
-asyncRam# wclk rclk en sz rd we wr din =
-    unsafeSynchronizer wclk rclk dout
+asyncRam# !_ !_ en sz rd we wr din = dout
   where
-    rd'  = unsafeSynchronizer rclk wclk rd
     ramI = Seq.replicate
-              (snatToNum sz)
+              szI
               (withFrozenCallStack (errorX "asyncRam#: initial value undefined"))
-    en' = fromEnable (enable en we)
-    dout = go ramI rd' en' wr din
+    en0 = fromEnable (enable en we)
+    dout = if rPeriod == wPeriod
+           then goSingle ramI rd en0 wr din
+           else go 0 ramI rd en0 wr din
+    rPeriod = snatToNum (clockPeriod @rdom) :: Int
+    wPeriod = snatToNum (clockPeriod @wdom) :: Int
+    szI = snatToNum sz :: Int
 
-    go :: Seq.Seq a -> Signal wdom Int -> Signal wdom Bool
-       -> Signal wdom Int -> Signal wdom a -> Signal wdom a
-    go !ram (r :- rs) (e :- es) (w :- ws) (d :- ds) =
-      let ram' = upd ram e (fromEnum w) d
+    goSingle :: Seq.Seq a -> Signal rdom Int -> Signal wdom Bool
+       -> Signal wdom Int -> Signal wdom a -> Signal rdom a
+    goSingle !ram (r :- rs) ~(e :- es) wt@(~(w :- ws)) dt@(~(d :- ds)) =
+      let ram0 = upd ram e w d
           o    = ram `Seq.index` r
-      in  o :- go ram' rs es ws ds
+      in  o :- (wt `seq` dt `seq` goSingle ram0 rs es ws ds)
 
-    upd ram we' waddr d = case maybeIsX we' of
+    -- Given
+    --   tR = absolute time of next active edge of read clock
+    --   tW = absolute time of next active edge of write clock
+    -- relTime is defined as relTime = tW - tR
+    --
+    -- Put differently, relative time 0 points at the next active edge of the
+    -- read clock, and relTime points at the next active edge of the write
+    -- clock.
+    go :: Int -> Seq.Seq a -> Signal rdom Int -> Signal wdom Bool
+       -> Signal wdom Int -> Signal wdom a -> Signal rdom a
+    go   relTime !ram rt@(~(r :- rs)) et@(~(e :- es)) wt@(~(w :- ws))
+         dt@(~(d :- ds))
+      | relTime < 0 = let ram0 = upd ram e w d
+                      in wt `seq` dt `seq`
+                         go (relTime + wPeriod) ram0 rt es ws ds
+      | otherwise   = let o = ram `Seq.index` r
+                      in o :- go (relTime - rPeriod) ram rs et wt dt
+
+    upd ram we0 waddr d = case maybeIsX we0 of
       Nothing -> case maybeIsX waddr of
-        Nothing -> fmap (const (seq waddr d)) ram
-        Just wa -> Seq.update wa d ram
+        Nothing -> -- Put the XException from `waddr` as the value in all
+                   -- locations of `ram`.
+                   seq waddr d <$ ram
+        Just wa -> -- Put the XException from `we` as the value at address
+                   -- `waddr`.
+                   Seq.update wa (seq we0 d) ram
       Just True -> case maybeIsX waddr of
-        Nothing -> fmap (const (seq waddr d)) ram
-        Just wa -> Seq.update wa d ram
+        Nothing -> -- Put the XException from `waddr` as the value in all
+                   -- locations of `ram`.
+                   seq waddr d <$ ram
+        Just wa -> d `seqX` Seq.update wa d ram
       _ -> ram
 {-# NOINLINE asyncRam# #-}
diff --git a/src/Clash/Explicit/ROM.hs b/src/Clash/Explicit/ROM.hs
--- a/src/Clash/Explicit/ROM.hs
+++ b/src/Clash/Explicit/ROM.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017     , Google Inc.
-                  2019     , Myrtle Software Ltd
+                  2019     , Myrtle Software Ltd,
+                  2022     , QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 ROMs
 -}
@@ -40,7 +41,8 @@
 -- | A ROM with a synchronous read port, with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
@@ -66,7 +68,8 @@
 -- | A ROM with a synchronous read port, with space for @n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
@@ -79,7 +82,7 @@
   -> Enable dom
   -- ^ Global enable
   -> Vec n a
-  -- ^ ROM content
+  -- ^ ROM content, also determines the size, @n@, of the ROM
   --
   -- __NB:__ must be a constant
   -> Signal dom addr
@@ -98,7 +101,7 @@
   -> Enable dom
   -- ^ Global enable
   -> Vec n a
-  -- ^ ROM content
+  -- ^ ROM content, also determines the size, @n@, of the ROM
   --
   -- __NB:__ must be a constant
   -> Signal dom Int
diff --git a/src/Clash/Explicit/ROM/File.hs b/src/Clash/Explicit/ROM/File.hs
--- a/src/Clash/Explicit/ROM/File.hs
+++ b/src/Clash/Explicit/ROM/File.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017     , Google Inc.
-                  2019     , Myrtle Software Ltd.
+                  2019     , Myrtle Software Ltd.,
+                  2022     , QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 = Initializing a ROM with a data file #usingromfiles#
 
@@ -99,7 +100,8 @@
 -- | A ROM with a synchronous read port, with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
@@ -139,7 +141,8 @@
 -- | A ROM with a synchronous read port, with space for @n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
diff --git a/src/Clash/Explicit/Reset.hs b/src/Clash/Explicit/Reset.hs
--- a/src/Clash/Explicit/Reset.hs
+++ b/src/Clash/Explicit/Reset.hs
@@ -64,7 +64,7 @@
 -- be de-asserted synchronously but it can still be asserted asynchronously.
 -- The reset assert is immediate, but reset de-assertion is delayed by two
 -- cycles.
-
+--
 -- Normally, asynchronous resets can be both asynchronously asserted and
 -- de-asserted. Asynchronous de-assertion can induce meta-stability in the
 -- component which is being reset. To ensure this doesn't happen,
diff --git a/src/Clash/Intel/ClockGen.hs b/src/Clash/Intel/ClockGen.hs
--- a/src/Clash/Intel/ClockGen.hs
+++ b/src/Clash/Intel/ClockGen.hs
@@ -38,6 +38,8 @@
 -- -- outputs a clock running at 100 MHz
 -- altpll @@"50MHzDom" @@"100MHzDom" (SSymbol @@"altpll50to100") clk50 rst
 -- @
+--
+-- See also the [ALTPLL (Phase-Locked Loop) IP Core User Guide](https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altpll.pdf)
 altpll
   :: forall domOut domIn name
    . (KnownDomain domIn, KnownDomain domOut)
@@ -81,6 +83,8 @@
 -- @
 --
 -- respectively.
+--
+-- See also the [Altera Phase-Locked Loop (Altera PLL) IP Core User Guide](https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/altera_pll.pdf)
 alteraPll
   :: (Clocks t, KnownDomain domIn, ClocksCxt t)
   => SSymbol name
diff --git a/src/Clash/Prelude/BlockRam.hs b/src/Clash/Prelude/BlockRam.hs
--- a/src/Clash/Prelude/BlockRam.hs
+++ b/src/Clash/Prelude/BlockRam.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2013-2016, University of Twente,
                   2016-2019, Myrtle Software Ltd,
-                  2017     , Google Inc.
+                  2017     , Google Inc.,
+                  2021-2022, QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 BlockRAM primitives
 
@@ -231,10 +232,10 @@
 
 Again, we can simulate our system and see that it works. This time however,
 we need to disregard the first few output samples, because the initial content of an
-'Clash.Prelude.RAM.asyncRam' is 'Clash.XException.undefined', and consequently, the first few
-output samples are also 'Clash.XException.undefined'. We use the utility function
+'Clash.Prelude.RAM.asyncRam' is /undefined/, and consequently, the first few
+output samples are also /undefined/. We use the utility function
 'Clash.XException.printX' to conveniently filter out the undefinedness and
-replace it with the string "X" in the few leading outputs.
+replace it with the string @\"undefined\"@ in the few leading outputs.
 
 @
 >>> printX $ sampleN @System 32 (system2 prog)
@@ -362,8 +363,8 @@
 
 When we simulate our system we see that it works. This time again,
 we need to disregard the first sample, because the initial output of a
-'blockRam' is 'Clash.XException.undefined'. We use the utility function 'Clash.XException.printX'
-to conveniently filter out the undefinedness and replace it with the string "X".
+'blockRam' is /undefined/. We use the utility function 'Clash.XException.printX'
+to conveniently filter out the undefinedness and replace it with the string @\"undefined\"@.
 
 @
 >>> printX $ sampleN @System 34 (system3 prog2)
@@ -673,7 +674,8 @@
 -- | Create a blockRAM with space for @n@ elements.
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'Clash.XException.undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- @
 -- bram40
@@ -770,7 +772,8 @@
 -- | Create a blockRAM with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'Clash.XException.undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- @
 -- bram32
@@ -794,7 +797,7 @@
      , KnownNat n
      )
   => Vec (2^n) a
-  -- ^ Initial content of the BRAM, also determines the size, @2^n@, of the BRAM.
+  -- ^ Initial content of the BRAM
   --
   -- __NB__: __MUST__ be a constant.
   -> Signal dom (Unsigned n)
diff --git a/src/Clash/Prelude/BlockRam/File.hs b/src/Clash/Prelude/BlockRam/File.hs
--- a/src/Clash/Prelude/BlockRam/File.hs
+++ b/src/Clash/Prelude/BlockRam/File.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2019     , Myrtle Software Ltd
-                  2017     , Google Inc.
+                  2017     , Google Inc.,
+                  2022     , QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 = Initializing a BlockRAM with a data file #usingramfiles#
 
@@ -97,7 +98,8 @@
 -- | Create a blockRAM with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
@@ -143,7 +145,8 @@
 -- | Create a blockRAM with space for @n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
diff --git a/src/Clash/Prelude/RAM.hs b/src/Clash/Prelude/RAM.hs
--- a/src/Clash/Prelude/RAM.hs
+++ b/src/Clash/Prelude/RAM.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017-2019, Myrtle Software Ltd
-                  2017     , Google Inc.
+                  2017     , Google Inc.,
+                  2021-2022, QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 RAM primitives with a combinational read port.
 -}
@@ -34,7 +35,8 @@
 
 -- | Create a RAM with space for @n@ elements.
 --
--- * __NB__: Initial content of the RAM is 'undefined'
+-- * __NB__: Initial content of the RAM is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
@@ -60,7 +62,8 @@
 
 -- | Create a RAM with space for 2^@n@ elements
 --
--- * __NB__: Initial content of the RAM is 'undefined'
+-- * __NB__: Initial content of the RAM is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
diff --git a/src/Clash/Prelude/ROM.hs b/src/Clash/Prelude/ROM.hs
--- a/src/Clash/Prelude/ROM.hs
+++ b/src/Clash/Prelude/ROM.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017     , Google Inc.
-                  2019     , Myrtle Software Ltd
+                  2019     , Myrtle Software Ltd,
+                  2021-2022, QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 ROMs
 -}
@@ -48,7 +49,7 @@
 asyncRom
   :: (KnownNat n, Enum addr)
   => Vec n a
-  -- ^ ROM content
+  -- ^ ROM content, also determines the size, @n@, of the ROM
   --
   -- __NB:__ must be a constant
   -> addr
@@ -81,7 +82,7 @@
 asyncRom#
   :: KnownNat n
   => Vec n a
-  -- ^ ROM content
+  -- ^ ROM content, also determines the size, @n@, of the ROM
   --
   -- __NB:__ must be a constant
   -> Int
@@ -111,7 +112,7 @@
      , HiddenClock dom
      , HiddenEnable dom  )
   => Vec n a
-  -- ^ ROM content
+  -- ^ ROM content, also determines the size, @n@, of the ROM
   --
   -- __NB:__ must be a constant
   -> Signal dom (Unsigned m)
@@ -124,7 +125,8 @@
 -- | A ROM with a synchronous read port, with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 --
 -- Additional helpful information:
 --
diff --git a/src/Clash/Prelude/ROM/File.hs b/src/Clash/Prelude/ROM/File.hs
--- a/src/Clash/Prelude/ROM/File.hs
+++ b/src/Clash/Prelude/ROM/File.hs
@@ -1,9 +1,10 @@
 {-|
 Copyright  :  (C) 2015-2016, University of Twente,
                   2017     , Google Inc.
-                  2019     , Myrtle Software Ltd
+                  2019     , Myrtle Software Ltd,
+                  2022     , QBayLogic B.V.
 License    :  BSD2 (see the file LICENSE)
-Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
 
 = Initializing a ROM with a data file #usingromfiles#
 
@@ -149,7 +150,7 @@
   -> BitVector m
   -- ^ The value of the ROM at address @rd@
 asyncRomFile sz file = asyncRomFile# sz file . fromEnum
--- Leave 'asyncRom' eta-reduced, see Note [Eta-reduction and unsafePerformIO initMem]
+-- Leave 'asyncRomFile#' eta-reduced, see Note [Eta-reduction and unsafePerformIO initMem]
 {-# INLINE asyncRomFile #-}
 
 -- Note [Eta-reduction and unsafePerformIO initMem]
@@ -248,7 +249,8 @@
 -- | A ROM with a synchronous read port, with space for @n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
@@ -289,7 +291,8 @@
 -- | A ROM with a synchronous read port, with space for 2^@n@ elements
 --
 -- * __NB__: Read value is delayed by 1 cycle
--- * __NB__: Initial output value is 'undefined'
+-- * __NB__: Initial output value is /undefined/, reading it will throw an
+-- 'Clash.XException.XException'
 -- * __NB__: This function might not work for specific combinations of
 -- code-generation backends and hardware targets. Please check the support table
 -- below:
diff --git a/src/Clash/Signal/Bundle/Internal.hs b/src/Clash/Signal/Bundle/Internal.hs
--- a/src/Clash/Signal/Bundle/Internal.hs
+++ b/src/Clash/Signal/Bundle/Internal.hs
@@ -1,9 +1,9 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE TemplateHaskell #-}
 
-module Clash.Signal.Bundle.Internal where
+module Clash.Signal.Bundle.Internal (deriveBundleTuples, idPrimitive) where
 
-import           Control.Monad               (liftM)
+import           Control.Monad.Extra         (concatMapM)
 import           Clash.Annotations.Primitive (Primitive(InlinePrimitive))
 import           Clash.CPP                   (maxTupleSize)
 import           Clash.Signal.Internal       (Signal((:-)))
@@ -20,10 +20,6 @@
   ipJson = "[{\"Primitive\": {\"name\": \"" ++ show nm ++ "\", \"primType\": \"Function\"}}]"
   ip = InlinePrimitive [minBound..maxBound] ipJson
 
--- | Monadic version of concatMap
-concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
-concatMapM f xs = liftM concat (mapM f xs)
-
 -- | Contruct all the tuple instances for Bundle.
 deriveBundleTuples
   :: Name
@@ -162,7 +158,7 @@
            , unbundleSig, unbundleF, unbundlePrimAnn, unbundleNoInlineAnn
            ]
 
-mkFunTys :: Foldable t => t Type -> Type -> Type
+mkFunTys :: Foldable t => t TH.Type -> TH.Type -> TH.Type
 mkFunTys args res= foldl' go res args
  where
   go l r = AppT (AppT ArrowT l) r
diff --git a/src/Clash/Signal/Internal.hs b/src/Clash/Signal/Internal.hs
--- a/src/Clash/Signal/Internal.hs
+++ b/src/Clash/Signal/Internal.hs
@@ -854,7 +854,7 @@
 clockTag (Clock dom) = dom
 
 -- | Clock generator for simulations. Do __not__ use this clock generator for
--- for the /testBench/ function, use 'Clash.Explicit.Testbench.tbClockGen' instead.
+-- the /testBench/ function, use 'Clash.Explicit.Testbench.tbClockGen' instead.
 --
 -- To be used like:
 --
diff --git a/src/Clash/Sized/Internal/BitVector.hs b/src/Clash/Sized/Internal/BitVector.hs
--- a/src/Clash/Sized/Internal/BitVector.hs
+++ b/src/Clash/Sized/Internal/BitVector.hs
@@ -153,7 +153,7 @@
 import GHC.Natural                (naturalToInteger)
 #endif
 import GHC.Prim                   (dataToTag#)
-import GHC.Stack                  (HasCallStack, withFrozenCallStack)
+import GHC.Stack                  (withFrozenCallStack)
 import GHC.TypeLits               (KnownNat, Nat, type (+), type (-))
 #if MIN_VERSION_base(4,15,0)
 import GHC.TypeNats               (natVal)
@@ -1179,35 +1179,35 @@
 
 
 -- error for infix operator
-undefErrorI :: (HasCallStack, KnownNat m, KnownNat n) => String -> BitVector m -> BitVector n -> a
+undefErrorI :: (KnownNat m, KnownNat n) => String -> BitVector m -> BitVector n -> a
 undefErrorI op bv1 bv2 = withFrozenCallStack $
   errorX $ "Clash.Sized.BitVector." ++ op
   ++ " called with (partially) undefined arguments: "
   ++ show bv1 ++ " " ++ op ++" " ++ show bv2
 
 -- error for prefix operator/function
-undefErrorP :: (HasCallStack, KnownNat m, KnownNat n) => String -> BitVector m -> BitVector n -> a
+undefErrorP :: (KnownNat m, KnownNat n) => String -> BitVector m -> BitVector n -> a
 undefErrorP op bv1 bv2 = withFrozenCallStack $
   errorX $ "Clash.Sized.BitVector." ++ op
   ++ " called with (partially) undefined arguments: "
   ++ show bv1 ++ " " ++ show bv2
 
 -- error for prefix operator/function
-undefErrorP3 :: (HasCallStack, KnownNat m, KnownNat n, KnownNat o) => String -> BitVector m -> BitVector n -> BitVector o -> a
+undefErrorP3 :: (KnownNat m, KnownNat n, KnownNat o) => String -> BitVector m -> BitVector n -> BitVector o -> a
 undefErrorP3 op bv1 bv2 bv3 = withFrozenCallStack $
   errorX $ "Clash.Sized.BitVector." ++ op
   ++ " called with (partially) undefined arguments: "
   ++ show bv1 ++ " " ++ show bv2 ++ " " ++ show bv3
 
 -- error for unary operator/function
-undefErrorU :: (HasCallStack, KnownNat n) => String -> BitVector n -> a
+undefErrorU :: KnownNat n => String -> BitVector n -> a
 -- undefErrorU op bv1 = undefError ("Clash.Sized.BitVector." ++ op) [bv1]
 undefErrorU op bv1 = withFrozenCallStack $
   errorX $ "Clash.Sized.BitVector." ++ op
   ++ " called with (partially) undefined argument: "
   ++ show bv1
 
-undefError :: (HasCallStack, KnownNat n) => String -> [BitVector n] -> a
+undefError :: KnownNat n => String -> [BitVector n] -> a
 undefError op bvs = withFrozenCallStack $
   errorX $ op
   ++ " called with (partially) undefined arguments: "
diff --git a/src/Clash/Sized/Internal/BitVector.hs-boot b/src/Clash/Sized/Internal/BitVector.hs-boot
--- a/src/Clash/Sized/Internal/BitVector.hs-boot
+++ b/src/Clash/Sized/Internal/BitVector.hs-boot
@@ -10,11 +10,10 @@
 module Clash.Sized.Internal.BitVector where
 
 import GHC.TypeLits (KnownNat,Nat)
-import GHC.Stack    (HasCallStack)
 import Data.Kind    (Type)
 
 type role BitVector nominal
 data BitVector :: Nat -> Type
 data Bit
 
-undefError :: (HasCallStack, KnownNat n) => String -> [BitVector n] -> a
+undefError :: KnownNat n => String -> [BitVector n] -> a
diff --git a/src/Clash/Sized/RTree.hs b/src/Clash/Sized/RTree.hs
--- a/src/Clash/Sized/RTree.hs
+++ b/src/Clash/Sized/RTree.hs
@@ -336,7 +336,7 @@
 import Data.Singletons
 import Data.Proxy
 
-data IIndex (f :: 'TyFun' Nat *) :: *
+data IIndex (f :: 'TyFun' Nat Type) :: Type
 type instance 'Apply' IIndex l = 'Index' ((2^l)+1)
 
 populationCount' :: (KnownNat k, KnownNat (2^k))
diff --git a/src/Clash/Sized/Vector.hs b/src/Clash/Sized/Vector.hs
--- a/src/Clash/Sized/Vector.hs
+++ b/src/Clash/Sized/Vector.hs
@@ -2130,7 +2130,7 @@
 -- import Data.Singletons
 -- import Data.Proxy
 --
--- data Append (m :: Nat) (a :: *) (f :: 'TyFun' Nat *) :: *
+-- data Append (m :: Nat) (a :: Type) (f :: 'TyFun' Nat Type) :: Type
 -- type instance 'Apply' (Append m a) l = 'Vec' (l + m) a
 --
 -- append' xs ys = 'dfold' (Proxy :: Proxy (Append m a)) (const (':>')) ys xs
@@ -2164,7 +2164,7 @@
   where
     go :: SNat n -> Vec n a -> (p @@ n)
     go _ Nil                        = z
-    go s (y `Cons` (ys :: Vec z a)) =
+    go s (y `Cons` ys) =
       let s' = s `subSNat` d1
       in  f s' y (go s' ys)
 {-# NOINLINE dfold #-}
@@ -2260,7 +2260,7 @@
 import Data.Singletons
 import Data.Proxy
 
-data IIndex (f :: 'TyFun' Nat *) :: *
+data IIndex (f :: 'TyFun' Nat Type) :: Type
 type instance 'Apply' IIndex l = 'Index' ((2^l)+1)
 
 populationCount' :: (KnownNat k, KnownNat (2^k))
diff --git a/src/Clash/Tutorial.hs b/src/Clash/Tutorial.hs
--- a/src/Clash/Tutorial.hs
+++ b/src/Clash/Tutorial.hs
@@ -906,24 +906,24 @@
 import "Clash.Intel.ClockGen"
 
 'createDomain' vSystem{vName=\"DomInput\", vPeriod=20000}
-'createDomain' vSystem{vName=\"Dom50\", vPeriod=50000}
+'createDomain' vSystem{vName=\"Dom100\", vPeriod=10000}
 
 topEntity
   :: Clock DomInput
   -> Signal DomInput Bool
-  -> Signal Dom50 Bit
-  -> Signal Dom50 (BitVector 8)
+  -> Signal Dom100 Bit
+  -> Signal Dom100 (BitVector 8)
 topEntity clk rst =
     'exposeClockResetEnable' ('mealy' blinkerT (1,False,0) . Clash.Prelude.isRising 1) pllOut rstSync 'enableGen'
   where
-    (pllOut,pllStable) = 'Clash.Intel.ClockGen.altpll' \@Dom50 (SSymbol \@\"altpll50\") clk ('Clash.Signal.unsafeFromLowPolarity' rst)
+    (pllOut,pllStable) = 'Clash.Intel.ClockGen.altpll' \@Dom100 (SSymbol \@\"altpll100\") clk ('Clash.Signal.unsafeFromLowPolarity' rst)
     rstSync            = 'Clash.Signal.resetSynchronizer' pllOut ('Clash.Signal.unsafeFromLowPolarity' pllStable) enableGen
 
 blinkerT (leds,mode,cntr) key1R = ((leds',mode',cntr'),leds)
   where
-    -- clock frequency = 50e6  (50 MHz)
+    -- clock frequency = 100e6  (100 MHz)
     -- led update rate = 333e-3 (every 333ms)
-    cnt_max = 16650000 :: ('Index' 16650001) -- 50e6 * 333e-3
+    cnt_max = 'maxBound' :: ('Index' 33300000) -- 100e6 * 333e-3
 
     cntr' | cntr == cnt_max = 0
           | otherwise       = cntr + 1
@@ -946,17 +946,17 @@
 use IEEE.MATH_REAL.ALL;
 use std.textio.all;
 use work.all;
-use work.blinker_types.all;
+use work.Blinker_topEntity_types.all;
 
-entity topentity is
+entity topEntity is
   port(-- clock
-       clk  : in blinker_types.clk_dominput;
-       rst  : in boolean;
-       x    : in std_logic;
-       leds : out std_logic_vector(7 downto 0));
+       clk    : in Blinker_topEntity_types.clk_DomInput;
+       rst    : in boolean;
+       x      : in std_logic;
+       result : out std_logic_vector(7 downto 0));
 end;
 
-architecture structural of topentity is
+architecture structural of topEntity is
  ...
 end;
 @
@@ -1458,7 +1458,7 @@
 Clash supports designs multiple /clock/ (and /reset/) domains, though perhaps in
 a slightly limited form. What is possible is:
 
-* Create clock primitives, such as PPLs, which have an accompanying HDL primitive
+* Create clock primitives, such as PLLs, which have an accompanying HDL primitive
   (described <#primitives later on> in this tutorial).
 * Explicitly assign clocks to memory primitives.
 * Synchronize between differently-clocked parts of your design in a type-safe
@@ -1514,7 +1514,7 @@
 What this means is that when Clash converts your design to VHDL/(System)Verilog,
 you end up with a top-level module/entity with multiple clock and reset ports
 for the different clock domains. If you're targeting an FPGA, you can use e.g. a
-<https://www.altera.com/literature/ug/ug_altpll.pdf PPL> or
+<https://www.altera.com/literature/ug/ug_altpll.pdf PLL> or
 <http://www.xilinx.com/support/documentation/user_guides/ug472_7Series_Clocking.pdf MMCM>
 to provide the clock signals.
 
@@ -2176,7 +2176,7 @@
 
     @
     x =
-      case 'resetKind' @@'System' of
+      case 'resetKind' @'System' of
         SAsynchronous -> \'a\'
         SSynchronous -> \'b\'
     @
@@ -2393,41 +2393,41 @@
 import Clash.Prelude
 import Clash.Explicit.Testbench
 
-dotp :: SaturatingNum a
-     => Vec (n + 1) a
-     -> Vec (n + 1) a
+dotp :: 'SaturatingNum' a
+     => 'Vec' (n + 1) a
+     -> 'Vec' (n + 1) a
      -> a
-dotp as bs = fold boundedAdd (zipWith boundedMul as bs)
+dotp as bs = 'fold' 'boundedAdd' ('zipWith' 'boundedMul' as bs)
 
 fir
-  :: ( HiddenClockResetEnable dom
-     , Default a
-     , KnownNat n
-     , SaturatingNum a
-     , NFDataX a )
-  => Vec (n + 1) a -> Signal dom a -> Signal dom a
+  :: ( 'HiddenClockResetEnable' dom
+     , 'KnownNat' n
+     , 'SaturatingNum' a
+     , 'NFDataX' a
+     , 'Default' a )
+  => 'Vec' (n + 1) a -> 'Signal' dom a -> 'Signal' dom a
 fir coeffs x_t = y_t
   where
-    y_t = dotp coeffs \<$\> bundle xs
-    xs  = window x_t
+    y_t = dotp coeffs \<$\> 'bundle' xs
+    xs  = 'window' x_t
 
 topEntity
-  :: Clock  System
-  -> Reset  System
-  -> Enable System
-  -> Signal System (Signed 16)
-  -> Signal System (Signed 16)
-topEntity = exposeClockResetEnable (fir (2:>3:>(-2):>8:>Nil))
+  :: 'Clock'  'System'
+  -> 'Reset'  'System'
+  -> 'Enable' 'System'
+  -> 'Signal' 'System' ('Signed' 16)
+  -> 'Signal' 'System' ('Signed' 16)
+topEntity = 'exposeClockResetEnable' (fir (2:>3:>(-2):>8:>'Nil'))
 {\-\# NOINLINE topEntity \#-\}
 
-testBench :: Signal System Bool
+testBench :: 'Signal' 'System' 'Bool'
 testBench = done
   where
-    testInput      = stimuliGenerator clk rst (2:>3:>(-2):>8:>Nil)
-    expectedOutput = outputVerifier' clk rst (4:>12:>1:>20:>Nil)
-    done           = expectedOutput (topEntity clk rst enableGen testInput)
-    clk            = tbSystemClockGen (not \<$\> done)
-    rst            = systemResetGen
+    testInput      = 'stimuliGenerator' clk rst (2:>3:>(-2):>8:>'Nil')
+    expectedOutput = 'outputVerifier'' clk rst (4:>12:>1:>20:>'Nil')
+    done           = expectedOutput (topEntity clk rst 'enableGen' testInput)
+    clk            = 'tbSystemClockGen' (not \<$\> done)
+    rst            = 'systemResetGen'
 @
 
 ==== Blinker circuit
@@ -2487,102 +2487,38 @@
 @
 module Blinker where
 
-import Clash.Prelude
-import Clash.Intel.ClockGen
-
-data LedMode
-  = Rotate
-  -- ^ After some period, rotate active led to the left
-  | Complement
-  -- ^ After some period, turn on all disable LEDs, and vice versa
-  deriving (Generic, 'NFDataX')
-
--- Define a synthesis domain with a clock with a period of 20000 /ps/.
-'createDomain' 'vSystem'{vName=\"Input\", vPeriod=20000}
+import "Clash.Signal"
+import "Clash.Prelude"
+import "Clash.Intel.ClockGen"
 
--- Define a synthesis domain with a clock with a period of 50000 /ps/.
-'createDomain' 'vSystem'{vName=\"Dom50\", vPeriod=50000}
+'createDomain' vSystem{vName=\"DomInput\", vPeriod=20000}
+'createDomain' vSystem{vName=\"Dom100\", vPeriod=10000}
 
-{\-\# ANN topEntity
-  ('Synthesize'
-    { t_name   = \"blinker\"
-    , t_inputs = [ PortName \"CLOCK_50\"
-                 , PortName \"KEY0\"
-                 , PortName \"KEY1\"
-                 ]
-    , t_output = PortName \"LED\"
-    }) \#-\}
 topEntity
-  :: Clock Input
-  -- ^ Incoming clock
-  -> Signal Input Bool
-  -- ^ Reset signal, straight from KEY0
-  -> Signal Dom50 Bit
-  -- ^ Mode choice, straight from KEY1. See \'LedMode\'.
-  -> Signal Dom50 (BitVector 8)
-  -- ^ Output containing 8 bits, corresponding to 8 LEDs
-topEntity clk20 rstBtn modeBtn =
-  exposeClockResetEnable
-    (mealy blinkerT initialStateBlinkerT . isRising 1)
-    clk50
-    rstSync
-    en
-    modeBtn
- where
-  -- | Enable line for subcomponents: we'll keep it always running
-  en = enableGen
-
-  -- Start with the first LED turned on, in rotate mode, with the counter on zero
-  initialStateBlinkerT = (1, Rotate, 0)
-
-  -- Signal coming from the reset button is low when pressed, and high when
-  -- not pressed. We convert this signal to the polarity of our domain with
-  -- 'unsafeFromLowPolarity'.
-  rst = 'Clash.Signal.unsafeFromLowPolarity' rstBtn
-
-  -- Instantiate a PLL: this stabilizes the incoming clock signal and indicates
-  -- when the signal is stable. We're also using it to transform an incoming
-  -- clock signal running at 20 MHz to a clock signal running at 50 MHz.
-  (clk50, pllStable) =
-    altpll
-      \@Dom50
-      (SSymbol \@\"altpll50\")
-      clk20
-      rst
-
-  -- Synchronize reset to clock signal coming from PLL. We want the reset to
-  -- remain active while the PLL is NOT stable, hence the conversion with
-  -- 'unsafeFromLowPolarity'
-  rstSync =
-    'Clash.Signal.resetSynchronizer'
-      clk50
-      (unsafeFromLowPolarity pllStable)
-      en
-
-flipMode :: LedMode -> LedMode
-flipMode Rotate = Complement
-flipMode Complement = Rotate
+  :: Clock DomInput
+  -> Signal DomInput Bool
+  -> Signal Dom100 Bit
+  -> Signal Dom100 (BitVector 8)
+topEntity clk rst =
+    'exposeClockResetEnable' ('mealy' blinkerT (1,False,0) . Clash.Prelude.isRising 1) pllOut rstSync 'enableGen'
+  where
+    (pllOut,pllStable) = 'Clash.Intel.ClockGen.altpll' \@Dom100 (SSymbol \@\"altpll100\") clk ('Clash.Signal.unsafeFromLowPolarity' rst)
+    rstSync            = 'Clash.Signal.resetSynchronizer' pllOut ('Clash.Signal.unsafeFromLowPolarity' pllStable)
 
-blinkerT
-  :: (BitVector 8, LedMode, Index 16650001)
-  -> Bool
-  -> ((BitVector 8, LedMode, Index 16650001), BitVector 8)
-blinkerT (leds, mode, cntr) key1R = ((leds', mode', cntr'), leds)
+blinkerT (leds,mode,cntr) key1R = ((leds',mode',cntr'),leds)
   where
-    -- clock frequency = 50e6  (50 MHz)
+    -- clock frequency = 100e6  (100 MHz)
     -- led update rate = 333e-3 (every 333ms)
-    cnt_max = 16650000 :: Index 16650001 -- 50e6 * 333e-3
+    cnt_max = 'maxBound' :: ('Index' 33300000) -- 100e6 * 333e-3
 
     cntr' | cntr == cnt_max = 0
           | otherwise       = cntr + 1
 
-    mode' | key1R     = flipMode mode
+    mode' | key1R     = not mode
           | otherwise = mode
 
-    leds' | cntr == 0 =
-              case mode of
-                Rotate -> rotateL leds 1
-                Complement -> complement leds
+    leds' | cntr == 0 = if mode then complement leds
+                                else rotateL leds 1
           | otherwise = leds
 @
 -}
diff --git a/src/Clash/XException.hs b/src/Clash/XException.hs
--- a/src/Clash/XException.hs
+++ b/src/Clash/XException.hs
@@ -252,11 +252,11 @@
 
 -- | Fully evaluate a value, returning 'Nothing' if it throws 'XException'.
 --
--- > maybeX 42                  = Just 42
--- > maybeX (XException msg)    = Nothing
--- > maybeX (3, XException msg) = Nothing
--- > maybeX (3, _|_)            = _|_
--- > maybeX _|_                 = _|_
+-- > maybeHasX 42                  = Just 42
+-- > maybeHasX (XException msg)    = Nothing
+-- > maybeHasX (3, XException msg) = Nothing
+-- > maybeHasX (3, _|_)            = _|_
+-- > maybeHasX _|_                 = _|_
 --
 maybeHasX :: NFData a => a -> Maybe a
 maybeHasX = maybeX hasX
@@ -296,7 +296,7 @@
 -- > isX 42                  = Right 42
 -- > isX (XException msg)    = Left msg
 -- > isX (3, XException msg) = Right (3, XException msg)
--- > isX (3, _|_)            = (3, _|_)
+-- > isX (3, _|_)            = Right (3, _|_)
 -- > isX _|_                 = _|_
 isX :: a -> Either String a
 isX a =
diff --git a/tests/Clash/Tests/BlockRam.hs b/tests/Clash/Tests/BlockRam.hs
new file mode 100644
--- /dev/null
+++ b/tests/Clash/Tests/BlockRam.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Clash.Tests.BlockRam (tests) where
+
+import qualified Data.List as List
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import qualified Clash.Explicit.Prelude as E
+import Clash.Explicit.BlockRam (blockRam#)
+import Clash.Prelude
+
+primRam
+  :: Signal System Int
+  -> Signal System Bool
+  -> Signal System Int
+  -> Signal System Int
+  -> Signal System (Maybe Int)
+primRam rd we wr din =
+  maybeIsX <$> blockRam# clockGen enableGen (0 :> 1 :> Nil) rd we wr din
+
+type PrimSamples = [(Int, Bool, Int, Int, Maybe Int)]
+
+undefEn :: PrimSamples
+
+-- Undefined enable:
+--    The written-to address should read 'undefined', but other addresses
+--    should still have their data.
+
+--                               rd  enable     waddr      wdata      dout
+
+undefEn =                     [ ( 0, undefined, 0        , 2        , Nothing)
+                              , ( 0, False    , 0        , 3        , Just 0 )
+                              , ( 1, False    , 0        , 3        , Nothing)
+                              , ( 1, False    , 0        , 3        , Just 1 )
+                              ]
+
+primRamAssertion
+  :: PrimSamples
+  -> Assertion
+primRamAssertion samples = actual @?= expectedOutput
+ where
+  (rd, we, wr, din, expectedOutput) = List.unzip5 samples
+  actual = E.sampleN (List.length samples) $ primRam (fromList rd)
+                                                     (fromList we)
+                                                     (fromList wr)
+                                                     (fromList din)
+
+tests :: TestTree
+tests = testGroup "BlockRam"
+  [ testCase "Undefined enable" $ primRamAssertion undefEn
+  ]
diff --git a/tests/Clash/Tests/Ram.hs b/tests/Clash/Tests/Ram.hs
new file mode 100644
--- /dev/null
+++ b/tests/Clash/Tests/Ram.hs
@@ -0,0 +1,112 @@
+-- Assert correct behavior:
+--
+-- Undefined enable:
+--    The written-to address should read 'undefined', but other addresses
+--    should still have their data.
+--
+-- Undefined write address:
+--    All addresses should read 'undefined'.
+--
+-- Undefined write data:
+--    The written-to address should read 'undefined', but other addresses
+--    should still have their data.
+--
+-- Deasserted enable
+--    It shouldn't matter that other write inputs are 'undefined'.
+--
+-- Deasserted enable, OOB address
+--    It shouldn't matter that it is out of bounds.
+--
+-- Read address strictness
+--    If the read result is not used, out-of-bounds read address shouldn't
+--    matter (equivalent to issue #1458).
+
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Clash.Tests.Ram (tests) where
+
+import qualified Data.List as L
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import Clash.Explicit.Prelude
+import Clash.Explicit.RAM
+
+type Ram = (   Signal System Int
+            -> Signal System Bool
+            -> Signal System Int
+            -> Signal System Int
+            -> Signal System (Maybe Int)
+           )
+
+ram :: Ram
+ram rd we wr din =
+  maybeIsX <$> asyncRam# clockGen clockGen enableGen d2 rd we wr din
+
+maskOobRead :: Ram
+maskOobRead rd we wr din =
+  maybeIsX <$> mux (rd .<. 2) ram0 (pure 4)
+ where
+  ram0 = asyncRam# clockGen clockGen enableGen d2 rd we wr din
+
+type Samples = [(Int, Bool, Int, Int, Maybe Int)]
+
+initMem, undefEn, undefWAddr, undefWData, enFalse, enFalseOobWAddr,
+  oobRAddrStrict
+  :: Samples
+
+--                               rd  enable     waddr      wdata      dout
+initMem =                     [ ( 0, True     , 0        , 0        , Nothing)
+                              , ( 0, True     , 1        , 1        , Just 0 )
+                              ]
+
+undefEn = initMem <>          [ ( 0, undefined, 0        , 2        , Just 0 )
+                              , ( 0, False    , 0        , 3        , Nothing)
+                              , ( 1, False    , 0        , 3        , Just 1 )
+                              ]
+
+undefWAddr = initMem <>       [ ( 0, True     , undefined, 2        , Just 0 )
+                              , ( 0, False    , 0        , 3        , Nothing)
+                              , ( 1, False    , 0        , 3        , Nothing)
+                              ]
+
+undefWData = initMem <>       [ ( 0, True     , 0        , undefined, Just 0 )
+                              , ( 0, False    , 0        , 3        , Nothing)
+                              , ( 1, False    , 0        , 3        , Just 1 )
+                              ]
+
+enFalse = initMem <>          [ ( 0, False    , undefined, undefined, Just 0)
+                              , ( 0, False    , undefined, undefined, Just 0)
+                              , ( 1, False    , undefined, undefined, Just 1)
+                              ]
+
+enFalseOobWAddr = initMem <>  [ ( 0, False    , 255      , 2        , Just 0 )
+                              , ( 0, False    , 0        , 3        , Just 0 )
+                              , ( 1, False    , 0        , 3        , Just 1 )
+                              ]
+
+oobRAddrStrict = initMem <>   [ ( 1, False    , 0        , 3        , Just 1 )
+                              , ( 2, False    , 0        , 3        , Just 4 )
+                              , ( 0, False    , 0        , 3        , Just 0 )
+                              ]
+
+ramAssertion
+  :: Ram
+  -> Samples
+  -> Assertion
+ramAssertion ram0 samples = actual @?= expectedOutput
+ where
+  (rd, we, wr, din, expectedOutput) = L.unzip5 samples
+  actual = sampleN (L.length samples) $ ram0 (fromList rd)
+                                             (fromList we)
+                                             (fromList wr)
+                                             (fromList din)
+tests :: TestTree
+tests = testGroup "Ram"
+  [ testCase "Undefined enable" $ ramAssertion ram undefEn
+  , testCase "Undefined write address" $ ramAssertion ram undefWAddr
+  , testCase "Undefined write data" $ ramAssertion ram undefWData
+  , testCase "Deasserted enable" $ ramAssertion ram enFalse
+  , testCase "Deasserted enable, OOB address" $ ramAssertion ram enFalseOobWAddr
+  , testCase "Read address strictness" $ ramAssertion maskOobRead oobRAddrStrict
+  ]
diff --git a/tests/unittests.hs b/tests/unittests.hs
--- a/tests/unittests.hs
+++ b/tests/unittests.hs
@@ -5,10 +5,12 @@
 import qualified Clash.Tests.AutoReg
 import qualified Clash.Tests.BitPack
 import qualified Clash.Tests.BitVector
+import qualified Clash.Tests.BlockRam
 import qualified Clash.Tests.DerivingDataRepr
 import qualified Clash.Tests.Fixed
 import qualified Clash.Tests.FixedExhaustive
 import qualified Clash.Tests.NFDataX
+import qualified Clash.Tests.Ram
 import qualified Clash.Tests.Reset
 import qualified Clash.Tests.Resize
 import qualified Clash.Tests.Signal
@@ -25,10 +27,12 @@
   [ Clash.Tests.AutoReg.tests
   , Clash.Tests.BitPack.tests
   , Clash.Tests.BitVector.tests
+  , Clash.Tests.BlockRam.tests
   , Clash.Tests.DerivingDataRepr.tests
   , Clash.Tests.Fixed.tests
   , Clash.Tests.FixedExhaustive.tests
   , Clash.Tests.NFDataX.tests
+  , Clash.Tests.Ram.tests
   , Clash.Tests.Reset.tests
   , Clash.Tests.Resize.tests
   , Clash.Tests.Signal.tests
