diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for byte-order
 
+## 0.1.3.0 -- 2021-02-22
+
+* Add a module for big-endian access to pointers.
+* Add `Bytes` instances for `Word128` and `Word256`.
+
 ## 0.1.2.0 -- 2020-01-06
 
 * Add a `Bytes` instance for `Word`.
diff --git a/byte-order.cabal b/byte-order.cabal
--- a/byte-order.cabal
+++ b/byte-order.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: byte-order
-version: 0.1.2.0
+version: 0.1.3.0
 synopsis: Portable big-endian and little-endian conversions
 description:
   This library provides an interface to portably work with byte
@@ -19,6 +19,7 @@
 
 library
   exposed-modules:
+    Data.Primitive.Ptr.BigEndian
     Data.Primitive.ByteArray.BigEndian
     Data.Primitive.ByteArray.LittleEndian
     System.ByteOrder
@@ -27,6 +28,7 @@
     , base >=4.11.1.0 && <5
     , primitive >=0.6.4 && <0.8
     , primitive-unaligned >=0.1.1 && <0.2
+    , wide-word >=0.1.1 && <0.2
   hs-source-dirs: src
   default-language: Haskell2010
   ghc-options: -O2 -Wall
@@ -39,5 +41,6 @@
     , base
     , byte-order
     , primitive
+    , wide-word
   ghc-options: -Wall -O2
   default-language: Haskell2010
diff --git a/src/Data/Primitive/Ptr/BigEndian.hs b/src/Data/Primitive/Ptr/BigEndian.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Primitive/Ptr/BigEndian.hs
@@ -0,0 +1,34 @@
+-- | This is drop-in replacement for the read, write, and index functions
+-- present in @Data.Primitive.Ptr@. While the functions from those modules
+-- use native byte order, the functions in this one use big-endian byte order
+-- (most significant byte first).
+module Data.Primitive.Ptr.BigEndian
+  ( -- * Aligned
+    writeOffPtr
+  , readOffPtr
+  , indexOffPtr
+  ) where
+
+import Data.Primitive (Prim)
+import Data.Primitive.Ptr (Ptr)
+import Control.Monad.Primitive (PrimMonad)
+import System.ByteOrder (Bytes,toBigEndian,fromBigEndian)
+import qualified Data.Primitive.Ptr as PM
+
+-- | Write a primitive value to the pointer. The offset is given
+-- in elements of type @a@ rather than in bytes. The most significant
+-- byte in the value comes first.
+writeOffPtr :: (PrimMonad m, Prim a, Bytes a) => Ptr a -> Int -> a -> m ()
+writeOffPtr arr ix v = PM.writeOffPtr arr ix (toBigEndian v)
+
+-- | Read a primitive value from the pointer, interpreting the first
+-- byte as the most significant one. The offset is given in elements of
+-- type @a@ rather than in bytes.
+readOffPtr :: (PrimMonad m, Prim a, Bytes a) => Ptr a -> Int -> m a
+readOffPtr arr ix = fromBigEndian <$> PM.readOffPtr arr ix
+
+-- | Read a primitive value from the pointer, interpreting the first
+-- byte as the most significant one. The offset is given in elements of
+-- type @a@ rather than in bytes.
+indexOffPtr :: (Prim a, Bytes a) => Ptr a -> Int -> a
+indexOffPtr arr ix = fromBigEndian (PM.indexOffPtr arr ix)
diff --git a/src/System/ByteOrder/Class.hs b/src/System/ByteOrder/Class.hs
--- a/src/System/ByteOrder/Class.hs
+++ b/src/System/ByteOrder/Class.hs
@@ -16,6 +16,7 @@
 import Data.Int (Int8,Int16,Int32,Int64)
 import Data.Word (Word8,Word16,Word32,Word64)
 import Data.Word (byteSwap16,byteSwap32,byteSwap64)
+import Data.WideWord (Word128(Word128),Word256(Word256))
 import GHC.ByteOrder (ByteOrder(BigEndian,LittleEndian),targetByteOrder)
 import GHC.Word (Word(W#))
 
@@ -65,6 +66,26 @@
     LittleEndian -> byteSwap64
   toLittleEndian = case targetByteOrder of
     BigEndian -> byteSwap64
+    LittleEndian -> id
+
+instance Bytes Word128 where
+  {-# inline toBigEndian #-}
+  {-# inline toLittleEndian #-}
+  toBigEndian = case targetByteOrder of
+    BigEndian -> id
+    LittleEndian -> (\(Word128 hi lo) -> Word128 (byteSwap64 lo) (byteSwap64 hi))
+  toLittleEndian = case targetByteOrder of
+    BigEndian -> (\(Word128 hi lo) -> Word128 (byteSwap64 lo) (byteSwap64 hi))
+    LittleEndian -> id
+
+instance Bytes Word256 where
+  {-# inline toBigEndian #-}
+  {-# inline toLittleEndian #-}
+  toBigEndian = case targetByteOrder of
+    BigEndian -> id
+    LittleEndian -> (\(Word256 a b c d) -> Word256 (byteSwap64 d) (byteSwap64 c) (byteSwap64 b) (byteSwap64 a))
+  toLittleEndian = case targetByteOrder of
+    BigEndian -> (\(Word256 a b c d) -> Word256 (byteSwap64 d) (byteSwap64 c) (byteSwap64 b) (byteSwap64 a))
     LittleEndian -> id
 
 instance Bytes Word where
diff --git a/test/Unit.hs b/test/Unit.hs
--- a/test/Unit.hs
+++ b/test/Unit.hs
@@ -3,11 +3,15 @@
 {-# language ScopedTypeVariables #-}
 {-# language TypeApplications #-}
 
+import Control.Monad (when)
 import Data.Primitive.ByteArray
 import Data.Word
 import GHC.Exts (RealWorld)
 import System.ByteOrder
+import Data.WideWord (Word128)
 
+import qualified Data.Primitive.ByteArray.BigEndian as BE
+
 main :: IO ()
 main = do
   putStrLn "Start"
@@ -19,6 +23,10 @@
   testC
   putStrLn "D"
   testD
+  putStrLn "E"
+  testE
+  putStrLn "F"
+  testF
   putStrLn "Finished"
 
 testA :: IO ()
@@ -27,11 +35,10 @@
   marr <- newByteArray 4
   setByteArray marr 0 4 (0x00 :: Word8)
   writeByteArray marr 0 (Fixed @'LittleEndian payload)
-  let name = "testA"
-  expectByte name marr 0 0x67
-  expectByte name marr 1 0x45
-  expectByte name marr 2 0x23
-  expectByte name marr 3 0x01
+  expectByte "testA, byte 0" marr 0 0x67
+  expectByte "testA, byte 1" marr 1 0x45
+  expectByte "testA, byte 2" marr 2 0x23
+  expectByte "testA, byte 3" marr 3 0x01
 
 testB :: IO ()
 testB = do
@@ -67,17 +74,55 @@
   marr <- newByteArray 20
   setByteArray marr 0 20 (0x00 :: Word8)
   writeByteArray marr 0 (Fixed @'LittleEndian payload)
-  let name = "testA"
+  let name = "testD"
   expectByte name marr 0 0x67
   expectByte name marr 1 0x45
   expectByte name marr 2 0x23
   expectByte name marr 3 0x01
   expectByte name marr 4 0x00
 
+testE :: IO ()
+testE = do
+  marr <- newByteArray 8
+  writeByteArray marr 0 (0xFF :: Word8)
+  writeByteArray marr 1 (0xFF :: Word8)
+  writeByteArray marr 2 (0xFF :: Word8)
+  writeByteArray marr 3 (0xFF :: Word8)
+  writeByteArray marr 4 (0x00 :: Word8)
+  writeByteArray marr 5 (0x06 :: Word8)
+  writeByteArray marr 6 (0x96 :: Word8)
+  writeByteArray marr 7 (0x9c :: Word8)
+  r <- BE.readByteArray marr 1
+  let expected = 0x0006969c :: Word32
+  when (r /= expected) (fail "testE failed")
+
+testF :: IO ()
+testF = do
+  marr <- newByteArray 32
+  writeByteArray marr 16 (0x00 :: Word8)
+  writeByteArray marr 17 (0x01 :: Word8)
+  writeByteArray marr 18 (0x02 :: Word8)
+  writeByteArray marr 19 (0x03 :: Word8)
+  writeByteArray marr 20 (0x04 :: Word8)
+  writeByteArray marr 21 (0x05 :: Word8)
+  writeByteArray marr 22 (0x06 :: Word8)
+  writeByteArray marr 23 (0x07 :: Word8)
+  writeByteArray marr 24 (0x08 :: Word8)
+  writeByteArray marr 25 (0x09 :: Word8)
+  writeByteArray marr 26 (0x0A :: Word8)
+  writeByteArray marr 27 (0x0B :: Word8)
+  writeByteArray marr 28 (0x0C :: Word8)
+  writeByteArray marr 29 (0x0D :: Word8)
+  writeByteArray marr 30 (0x0E :: Word8)
+  writeByteArray marr 31 (0x0F :: Word8)
+  r <- BE.readByteArray marr 1
+  let expected = 0x000102030405060708090A0B0C0D0E0F :: Word128
+  when (r /= expected) (fail "testF failed")
+
 expectByte :: String -> MutableByteArray RealWorld -> Int -> Word8 -> IO ()
 expectByte name marr ix w = do
   v <- readByteArray marr ix
   if v == w
     then pure ()
-    else fail (name ++ ": byte " ++ show ix ++ " was wrong")
+    else fail (name ++ ": byte " ++ show ix ++ " was wrong, expected " ++ show w ++ " but got " ++ show v)
 
