diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,6 +1,5 @@
 module Main where
 
-import Data.Monoid ((<>))
 import HaskellWorks.Prim.Bits
 
 main :: IO ()
diff --git a/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -1,8 +1,6 @@
 module Main where
 
 import Criterion.Main
-import Data.Bits
-import Data.Monoid            ((<>))
 import Data.Word
 import HaskellWorks.Prim.Bits
 
diff --git a/doctest/DoctestDriver.hs b/doctest/DoctestDriver.hs
new file mode 100644
--- /dev/null
+++ b/doctest/DoctestDriver.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP #-}
+
+#if MIN_VERSION_GLASGOW_HASKELL(8,4,4,0)
+{-# OPTIONS_GHC -F -pgmF doctest-discover #-}
+#else
+module Main where
+
+import qualified System.IO as IO
+
+main :: IO ()
+main = IO.putStrLn "WARNING: doctest will not run on GHC versions earlier than 8.4.4"
+#endif
diff --git a/hw-prim-bits.cabal b/hw-prim-bits.cabal
--- a/hw-prim-bits.cabal
+++ b/hw-prim-bits.cabal
@@ -1,63 +1,93 @@
+cabal-version: 2.4
+
 name:                   hw-prim-bits
-version:                0.1.0.4
+version:                0.1.0.5
 synopsis:               Primitive support for bit manipulation
-description:            Please see README.md
+description:            Primitive support for bit manipulation. Please see README.md
 homepage:               https://github.com/githubuser/hw-prim-bits#readme
-license:                BSD3
+license:                BSD-3-Clause
 license-file:           LICENSE
 author:                 John Ky
 maintainer:             newhoggy@gmail.com
-copyright:              2017 John Ky
+copyright:              2017-2021 John Ky
 category:               Data
+tested-with:            GHC == 9.0.1, GHC == 8.10.7, GHC == 8.8.4, GHC == 8.6.5
 build-type:             Simple
 extra-source-files:     README.md
-cabal-version:          >= 1.10
 
+source-repository head
+  type:     git
+  location: https://github.com/haskell-works/hw-prim-bits
+
+common base                 { build-depends: base                 >= 4          && < 5      }
+
+common criterion            { build-depends: criterion                                      }
+common doctest              { build-depends: doctest              >= 0.16.2     && < 0.19   }
+common doctest-discover     { build-depends: doctest-discover     >= 0.2        && < 0.3    }
+common hedgehog             { build-depends: hedgehog                                       }
+common hspec                { build-depends: hspec                                          }
+common hw-hedgehog          { build-depends: hw-hedgehog          >= 0.1.0.1                }
+common hw-hspec-hedgehog    { build-depends: hw-hspec-hedgehog                              }
+common QuickCheck           { build-depends: QuickCheck                                     }
+common vector               { build-depends: vector                                         }
+
+common config
+  default-language:     Haskell2010
+
+common hw-prim-bits
+  build-depends:        hw-prim-bits
+
 library
+  import:               base, config
   hs-source-dirs:       src
   exposed-modules:      HaskellWorks.Prim.Bits
+                      , HaskellWorks.Prim.Bits.Emul
                       , HaskellWorks.Prim.Bits.Fast
                       , HaskellWorks.Prim.Bits.Slow
-  build-depends:        base >= 4.7 && < 5
-  default-language:     Haskell2010
   C-sources:            cbits/bits.c
   Include-dirs:         cbits
   Install-includes:     bits.h
 
 executable hw-prim-bits-exe
+  import:               base, config
+                      , hw-prim-bits
   hs-source-dirs:       app
   main-is:              Main.hs
   ghc-options:          -threaded -rtsopts -with-rtsopts=-N
-  build-depends:        base
-                      , hw-prim-bits
-  default-language:     Haskell2010
 
 test-suite hw-prim-bits-test
-  type:                 exitcode-stdio-1.0
-  hs-source-dirs:       test
-  main-is:              Spec.hs
-  other-modules:        HaskellWorks.Prim.BitsSpec
-  build-depends:        base
+  import:               base, config
                       , hedgehog
                       , hspec
-                      , hw-hedgehog                   >= 0.1.0.1
+                      , hw-hedgehog
                       , hw-hspec-hedgehog
                       , hw-prim-bits
                       , QuickCheck
+  type:                 exitcode-stdio-1.0
+  hs-source-dirs:       test
+  main-is:              Spec.hs
+  other-modules:        HaskellWorks.Prim.BitsSpec
+  build-tool-depends:   hspec-discover:hspec-discover
   ghc-options:          -threaded -rtsopts -with-rtsopts=-N
-  default-language:     Haskell2010
 
 benchmark bench
+    import:             base, config
+                      , criterion
+                      , hw-prim-bits
+                      , vector
     Type: exitcode-stdio-1.0
     HS-Source-Dirs: bench
     Main-Is: Main.hs
     GHC-Options: -Wall -O2
-    Default-Language: Haskell2010
-    Build-Depends:      base                          >= 4          && < 5
-                      , criterion
-                      , hw-prim-bits
-                      , vector
 
-source-repository head
-  type:     git
-  location: https://github.com/haskell-works/hw-prim-bits
+test-suite doctest
+  import:               base, config
+                      , doctest
+                      , doctest-discover
+                      , hw-prim-bits
+  default-language:     Haskell2010
+  type:                 exitcode-stdio-1.0
+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N
+  main-is:              DoctestDriver.hs
+  HS-Source-Dirs:       doctest
+  build-tool-depends:   doctest-discover:doctest-discover
diff --git a/src/HaskellWorks/Prim/Bits/Emul.hs b/src/HaskellWorks/Prim/Bits/Emul.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Prim/Bits/Emul.hs
@@ -0,0 +1,39 @@
+module HaskellWorks.Prim.Bits.Emul
+  ( pdep32
+  , pdep64
+  , pext32
+  , pext64
+  ) where
+
+import Data.Bits
+import Data.Int
+import Data.Word
+
+pdep64 :: Word64 -> Word64 -> Word64
+pdep64 = pdep64' 0
+
+pdep32 :: Word32 -> Word32 -> Word32
+pdep32 src mask = fromIntegral (pdep64 (fromIntegral src) (fromIntegral mask))
+
+pdep64' :: Word64 -> Word64 -> Word64 -> Word64
+pdep64' result src mask = if lowest /= 0
+  then pdep64' (result .|. (lsb .&. lowest)) (src `shiftR` 1) (mask .&. complement lowest)
+  else result
+  where lowest  = (-mask) .&. mask
+        lsb     = fromIntegral ((fromIntegral (src `shiftL` 63) :: Int64) `shiftR` 63)
+
+
+pext64 :: Word64 -> Word64 -> Word64
+pext64 = pext64' 0 0 0
+
+pext32 :: Word32 -> Word32 -> Word32
+pext32 src mask = fromIntegral (pext64 (fromIntegral src) (fromIntegral mask))
+
+pext64' :: Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
+pext64' result offset index src mask = if index /= 64
+  then if maskBit /= 0
+          then pext64' (result .|. (srcBit `shiftL` offset)) (offset + 1) (index + 1) src mask
+          else pext64'  result                               offset       (index + 1) src mask
+  else result
+  where srcBit  = (src  `shiftR` index) .&. 1
+        maskBit = (mask `shiftR` index) .&. 1
diff --git a/test/HaskellWorks/Prim/BitsSpec.hs b/test/HaskellWorks/Prim/BitsSpec.hs
--- a/test/HaskellWorks/Prim/BitsSpec.hs
+++ b/test/HaskellWorks/Prim/BitsSpec.hs
@@ -4,29 +4,30 @@
 import Hedgehog
 import Test.Hspec
 
+import qualified HaskellWorks.Prim.Bits.Emul as E
 import qualified HaskellWorks.Prim.Bits.Fast as F
 import qualified HaskellWorks.Prim.Bits.Slow as S
 import qualified Hedgehog.Gen                as G
 import qualified Hedgehog.Range              as R
 
-{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
-{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}
+{- HLINT ignore "Redundant do"        -}
+{- HLINT ignore "Reduce duplication"  -}
 
 spec :: Spec
 spec = describe "HaskellWorks.Prim.BitsSpec" $ do
   it "pdep64 behaves the same" $ require $ property $ do
     a <- forAll $ G.word64 R.constantBounded
     b <- forAll $ G.word64 R.constantBounded
-    S.pdep64 a b === F.pdep64 a b
+    E.pdep64 a b === S.pdep64 a b
   it "pdep32 behaves the same" $ require $ property $ do
     a <- forAll $ G.word32 R.constantBounded
     b <- forAll $ G.word32 R.constantBounded
-    S.pdep32 a b === F.pdep32 a b
+    E.pdep32 a b === S.pdep32 a b
   it "pext64 behaves the same" $ require $ property $ do
     a <- forAll $ G.word64 R.constantBounded
     b <- forAll $ G.word64 R.constantBounded
-    S.pext64 a b === F.pext64 a b
+    E.pext64 a b === S.pext64 a b
   it "pext32 behaves the same" $ require $ property $ do
     a <- forAll $ G.word32 R.constantBounded
     b <- forAll $ G.word32 R.constantBounded
-    S.pext32 a b === F.pext32 a b
+    E.pext32 a b === S.pext32 a b
