diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,7 +1,24 @@
 * Hackage: <http://hackage.haskell.org/package/crackNum>
 * GitHub:  <http://github.com/LeventErkok/crackNum/>
 
-* Latest Hackage released version: 3.27, 2026-08-20
+* Latest Hackage released version: 3.28, 2026-08-21
+
+### Version 3.28, 2026-08-21
+
+  * Add support for the E8M0 format, via `-fe8m0`. This is the shared scale of the OCP
+    Microscaling (MX) formats: the value that scales a block of MXFP8/MXFP6/MXFP4
+    elements, all of which crackNum already knew about. It is the mirror image of
+    FP4 (E0M3): where that format is all significand and no exponent, E8M0 is all
+    exponent and no significand, with no sign bit either. Every value it holds is
+    therefore a power of two, from 2^-127 to 2^127.
+
+    Note that it has no zero and no subnormals -- with nothing for the all-zero
+    encoding to mean, it simply denotes 2^-127 -- and no infinities. `0xFF` is its
+    one and only NaN. Negative inputs are rejected rather than saturated: with no
+    sign bit there is no direction to saturate towards, and clamping would quietly
+    turn a negative into a positive. Values outside the range, infinity included,
+    saturate to the nearest end-point, and anything that is not a power of two
+    rounds according to `-r`.
 
 ### Version 3.27, 2026-08-20
 
diff --git a/GUI/tclGUI/crackNum.tcl b/GUI/tclGUI/crackNum.tcl
--- a/GUI/tclGUI/crackNum.tcl
+++ b/GUI/tclGUI/crackNum.tcl
@@ -37,6 +37,7 @@
         {ffp4e0m3 "FP4 (E0M3)"  fixed    fp4e0m3}
         {fe4m3    "FP8 (E4M3)"  fixed    e4m3}
         {fe5m2    "FP8 (E5M2)"  fixed    e5m2}
+        {fe8m0    "FP8 (E8M0)"  fixed    e8m0}
         {fhp      "Half"        fixed    hp}
         {fbp      "Brain"       fixed    bp}
         {ftf32    "TF32"        fixed    tf32}
@@ -480,6 +481,7 @@
                 e5m2    { set state(selection) fe5m2 }
                 fp4     { set state(selection) ffp4 }
                 fp4e0m3 { set state(selection) ffp4e0m3 }
+                e8m0    { set state(selection) fe8m0 }
                 default {
                     if {[regexp {^(\d+)\+(\d+)$} $v _ e s]} {
                         set state(selection) fcs
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@
 -fe4m3      FP8, alternate (no infinities)              4             4
 -ffp4       FP4 (E2M1)                                  2             2
 -ffp4e0m3   FP4 (E0M3), sign-magnitude                  0             3
+-fe8m0      E8M0 (MX scale), exponent-only              8             0
 -fa+b       Arbitrary IEEE-754 float                    a             b
 ```
 
@@ -79,6 +80,13 @@
 sign-magnitude *integer*, holding a sign and a 3-bit magnitude. It covers -7 to 7,
 with both a positive and a negative zero, and has neither NaN nor Inf.
 
+E8M0 is the odd one out in the other direction: it is the shared scale of the OCP
+Microscaling (MX) formats, and is *all* exponent. With no sign bit and no
+significand, every value it holds is a power of two, from 2^-127 to 2^127. It has
+no zero and no subnormals -- an all-zero encoding means 2^-127, not zero -- and no
+infinities; `0xFF` is its one and only NaN. Negative inputs are rejected, and
+values outside its range saturate to the nearest end-point.
+
 Integers come in two flavors: `-iN` for a signed `N`-bit 2's complement integer,
 and `-wN` for an unsigned `N`-bit word. Both `N` and the arbitrary float sizes
 can be as large as you like, within machine-word limits.
@@ -228,6 +236,47 @@
             Note: Conversion from "-5" was exact. No rounding happened.
 ```
 
+### Example: Decode an E8M0 MX scale
+```
+$ crackNum -fe8m0 0xFE
+Satisfiable. Model:
+  DECODED = 1.7014118346046923e38 :: E8M0
+                  76543210
+                  ---E8---
+   Binary layout: 11111110
+      Hex layout: FE
+       Precision: 8 exponent bits, no significand
+            Sign: Positive (always)
+        Exponent: 127 (Stored: 254, Bias: 127)
+  Classification: FP_NORMAL
+          Binary: 0b1p+127
+           Octal: 0o2p+126
+         Decimal: 1.7014118346046923e38
+             Hex: 0x8p+124
+```
+
+### Example: Encode an E8M0 MX scale
+Only powers of two are representable, so everything else rounds according to `-r`:
+```
+$ crackNum -fe8m0 -- 10
+Satisfiable. Model:
+  ENCODED = 8.0 :: E8M0
+                  76543210
+                  ---E8---
+   Binary layout: 10000010
+      Hex layout: 82
+       Precision: 8 exponent bits, no significand
+            Sign: Positive (always)
+        Exponent: 3 (Stored: 130, Bias: 127)
+  Classification: FP_NORMAL
+          Binary: 0b1p+3
+           Octal: 0o1p+3
+         Decimal: 8.0
+             Hex: 0x8
+   Rounding mode: RNE: Round nearest ties to even.
+            Note: Original value of 10.0 was rounded to 8.0.
+```
+
 ### Example: Encode a TensorFloat-32 number
 ```
 $ crackNum -ftf32 2.5
@@ -414,6 +463,7 @@
      e4m3: FP8 format (Alternate) ( 4 +   4)
       fp4: FP4 format (E2M1)      ( 2 +   2)
   fp4e0m3: FP4 format (E0M3)      ( 0 +   3)
+     e8m0: FP8 format (MX scale)  ( 8 +   0)
 
 Examples:
  Encoding:
@@ -429,6 +479,7 @@
    crackNum -fe5m2    2.5                     -- encode as an E5M2 FP8 float
    crackNum -ffp4     2.5                     -- encode as an FP4 (E2M1) float
    crackNum -ffp4e0m3 3.5                     -- encode as an FP4 (E0M3) sign-magnitude integer
+   crackNum -fe8m0    2.5                     -- encode as an E8M0 MX scale (power of two)
    crackNum -fsp      0x3.2p5                 -- encode as single-precision from hex-float
 
  Decoding:
@@ -441,6 +492,7 @@
    crackNum -fhp      0x8000                  -- decode as a half-precision float
    crackNum -ffp4     0b0111                  -- decode as an FP4 (E2M1) float
    crackNum -ffp4e0m3 0b1101                  -- decode as an FP4 (E0M3) sign-magnitude integer
+   crackNum -fe8m0    0x7F                    -- decode as an E8M0 MX scale (power of two)
    crackNum -l4 -fhp  64\'hbdffaaffdc71fc60   -- decode as half-precision float over 4 lanes using verilog notation
 
  GUI:
@@ -458,6 +510,10 @@
        - FP4 (E0M3) is a sign-magnitude integer: a sign bit and a 3-bit magnitude,
          covering -7 to 7, with both a positive and a negative zero. It has no NaN
          and no Inf either, and values outside [-7, 7] saturate to the end-point.
+       - E8M0 (MX scale) is all exponent: no sign bit and no significand at all,
+         so every value is a power of two, from 2^-127 to 2^127. It has no zero
+         and no Inf, and 0xFF is its only NaN. Negative inputs are rejected;
+         values outside the range saturate to the nearest end-point.
    - For decoding:
        - Use hexadecimal (0x) binary (0b), or N'h (verilog) notation as input.
          Input must have one of these prefixes.
diff --git a/crackNum.cabal b/crackNum.cabal
--- a/crackNum.cabal
+++ b/crackNum.cabal
@@ -1,6 +1,6 @@
 Cabal-version      : 2.2
 Name               : crackNum
-Version            : 3.27
+Version            : 3.28
 Synopsis           : Crack various integer and floating-point data formats
 Description        : Crack IEEE-754 and other float formats and arbitrary sized words and integers, showing the layout.
                      .
diff --git a/crackNum.vim b/crackNum.vim
--- a/crackNum.vim
+++ b/crackNum.vim
@@ -39,7 +39,7 @@
 " Used only when crackNum is too old to know --list-formats, or is not on the PATH.
 " Anything crackNum has learned since is picked up from the executable, not from here.
 let s:crackNumFallbackFormats = [ "hp", "bp", "tf32", "sp", "dp", "qp"
-                              \ , "e5m2", "e4m3", "fp4", "fp4e0m3"
+                              \ , "e5m2", "e4m3", "fp4", "fp4e0m3", "e8m0"
                               \ ]
 
 " The formats the executable reports, as -f flags. Asking it keeps this list from
diff --git a/src/CrackNum/Main.hs b/src/CrackNum/Main.hs
--- a/src/CrackNum/Main.hs
+++ b/src/CrackNum/Main.hs
@@ -66,6 +66,7 @@
         | E4M3        -- Custom FP8 format with no infinities and limited NaNs
         | FP4         -- NVIDIA FP4 (E2M1) format with no infinities and no NaNs
         | FP4E0M3     -- 4-bit sign-magnitude integer format; no exponent at all
+        | E8M0        -- OCP MX scale format; no sign and no significand at all
         deriving (Show, Eq)
 
 -- | How many bits does this float occupy
@@ -77,6 +78,7 @@
 fpSize E4M3     = 8
 fpSize FP4      = 4
 fpSize FP4E0M3  = 4
+fpSize E8M0     = 8
 
 kSize :: NKind -> Int
 kSize (SInt  i)  = i
@@ -179,6 +181,7 @@
             , ("e4m3",    "FP8 format (Alternate)", "( 4 +   4)", True )
             , ("fp4",     "FP4 format (E2M1)",      "( 2 +   2)", True )
             , ("fp4e0m3", "FP4 format (E0M3)",      "( 0 +   3)", True )
+            , ("e8m0",    "FP8 format (MX scale)",  "( 8 +   0)", True )
             ]
 
 -- | The formats that can actually be named, i.e., everything but the arbitrary a+b
@@ -206,6 +209,7 @@
 getFP "e4m3"    = Floating E4M3
 getFP "fp4"     = Floating FP4
 getFP "fp4e0m3" = Floating FP4E0M3
+getFP "e8m0"    = Floating E8M0
 getFP ab        = case span isDigit ab of
                   (eb@(_:_), '+':r) -> case span isDigit r of
                                         (sp@(_:_), "") -> mkEBSB (read eb) (read sp)
@@ -289,6 +293,7 @@
                               , "   " ++ pn ++ " -fe5m2    2.5                     -- encode as an E5M2 FP8 float"
                               , "   " ++ pn ++ " -ffp4     2.5                     -- encode as an FP4 (E2M1) float"
                               , "   " ++ pn ++ " -ffp4e0m3 3.5                     -- encode as an FP4 (E0M3) sign-magnitude integer"
+                              , "   " ++ pn ++ " -fe8m0    2.5                     -- encode as an E8M0 MX scale (power of two)"
                               , "   " ++ pn ++ " -fsp      0x3.2p5                 -- encode as single-precision from hex-float"
                               , ""
                               , " Decoding:"
@@ -301,6 +306,7 @@
                               , "   " ++ pn ++ " -fhp      0x8000                  -- decode as a half-precision float"
                               , "   " ++ pn ++ " -ffp4     0b0111                  -- decode as an FP4 (E2M1) float"
                               , "   " ++ pn ++ " -ffp4e0m3 0b1101                  -- decode as an FP4 (E0M3) sign-magnitude integer"
+                              , "   " ++ pn ++ " -fe8m0    0x7F                    -- decode as an E8M0 MX scale (power of two)"
                               , "   " ++ pn ++ " -l4 -fhp  64\\'hbdffaaffdc71fc60   -- decode as half-precision float over 4 lanes using verilog notation"
                               , ""
                               , " GUI:"
@@ -318,6 +324,10 @@
                               , "       - FP4 (E0M3) is a sign-magnitude integer: a sign bit and a 3-bit magnitude,"
                               , "         covering -7 to 7, with both a positive and a negative zero. It has no NaN"
                               , "         and no Inf either, and values outside [-7, 7] saturate to the end-point."
+                              , "       - E8M0 (MX scale) is all exponent: no sign bit and no significand at all,"
+                              , "         so every value is a power of two, from 2^-127 to 2^127. It has no zero"
+                              , "         and no Inf, and 0xFF is its only NaN. Negative inputs are rejected;"
+                              , "         values outside the range saturate to the nearest end-point."
                               , "   - For decoding:"
                               , "       - Use hexadecimal (0x) binary (0b), or N'h (verilog) notation as input."
                               , "         Input must have one of these prefixes."
@@ -673,6 +683,7 @@
                      E4M3    -> de4m3 config allBits
                      FP4     -> dFP4  config allBits
                      FP4E0M3 -> decodeFP4E0M3 allBits
+                     E8M0    -> decodeE8M0 debug allBits
 
         dFloat :: [SBool] -> ConstraintSet
         dFloat  bs = do x <- sFloat "DECODED"
@@ -757,8 +768,6 @@
 
             modifiedResult = SBV.crack debug (literal sval :: SDouble)
 
-            isClassification = ("Classification:" `isInfixOf`)
-
             fixVal l = case [tag | tag <- ["ENCODED", "DECODED"], tag `isInfixOf` l] of
                          tag : _ -> "  " ++ tag ++ " = " ++ show sval ++ " :: " ++ show fmt
                          []      -> l
@@ -767,6 +776,19 @@
         mapM_ (putStrLn . fixVal) $ takeWhile (not . isClassification) (lines (show ieeeResult))
         mapM_ putStrLn            $ dropWhile (not . isClassification) (lines modifiedResult)
 
+-- | The line SBV's cracker prints the classification on. Everything from here down
+-- describes the value itself rather than its layout, which is the split the formats
+-- that deviate from IEEE need: they take the layout from the look-alike (or lay it
+-- out by hand) and the rest from the value they actually mean.
+isClassification :: String -> Bool
+isClassification = ("Classification:" `isInfixOf`)
+
+-- | SBV notes that a NaN's representation is not unique. That holds for IEEE formats,
+-- but not for the ones here that have exactly one NaN pattern (E4M3 and E8M0), so drop
+-- the note for those rather than claim an ambiguity the format does not have.
+dropNaNUniquenessNote :: [String] -> [String]
+dropNaNUniquenessNote = filter (not . ("Representation for NaN's is not unique" `isInfixOf`))
+
 -- | The canonical quiet-NaN pattern for a float with @eb@ exponent bits and @sb@
 -- significand bits (including the implicit one): sign 0, all-ones exponent, and only
 -- the leading stored significand bit set. For single-precision this is 0x7FC00000.
@@ -885,6 +907,8 @@
 
         ef FP4E0M3 _ = encodeFP4E0M3 rm inp
 
+        ef E8M0    _ = encodeE8M0 debug rm inp
+
 -- | Convert certain strings to more understandable format by read
 -- If first argument is True, then we're reading using reads, i.e., haskell syntax
 -- If first argument is False, then we're using big-float library, which has a different notion for infinity and nans
@@ -959,12 +983,9 @@
        fixEncoded :: SatResult -> String
        fixEncoded = retype E4M3
 
-       onEach f = intercalate "\n" . concatMap f . lines
-
        -- nan representation is unique for E4M3
-       fixNaN :: String -> [String]
-       fixNaN s | "Representation for NaN's is not unique" `isInfixOf` s = []
-                | True                                                   = [s]
+       fixNaN :: String -> String
+       fixNaN = intercalate "\n" . dropNaNUniquenessNote . lines
 
        getNaN = satWith config{crackNumSurfaceVals = [("ENCODED", 0x7F)]} $
                               do x :: SFloatingPoint 4 4 <- sFloatingPoint "ENCODED"
@@ -974,9 +995,9 @@
        analyze v
          -- NaN has two representations, with surface value S.1111.111; we use 0x7F for simplicity
          | isNaN v
-         = getNaN >>= putStrLn . onEach fixNaN . fixEncoded
+         = getNaN >>= putStrLn . fixNaN . fixEncoded
          | isInfinite v
-         = do getNaN >>= putStrLn . onEach fixNaN . fixEncoded
+         = do getNaN >>= putStrLn . fixNaN . fixEncoded
               putStrLn "            Note: The input value was infinite, which is not representable in E4M3."
          | True
          = range v
@@ -1023,7 +1044,7 @@
 
        range v
          | v < -448 || v > 448   -- Out-of-bounds becomes NaN
-         = do getNaN >>= putStrLn . onEach fixNaN . fixEncoded
+         = do getNaN >>= putStrLn . fixNaN . fixEncoded
               putStrLn $ "            Note: The input value " ++ show v ++ " is out of bounds, and hence becomes NaN"
               putStrLn   "                  The representable range is [-448, 448]"
 
@@ -1272,3 +1293,139 @@
                  = putStrLn $ "            Note: Conversion from " ++ show inp ++ " was exact. No rounding happened."
                  | True
                  = putStrLn $ "            Note: Original value of " ++ show v ++ " was rounded to " ++ t ++ "."
+
+-- | E8M0 is the OCP Microscaling (MX) scale format: the value that scales a block of
+-- MXFP8/MXFP6/MXFP4 elements. All 8 bits are exponent -- there is no sign bit and no
+-- significand at all -- so every value is the power of two 2^(E-127), and 0xFF is its
+-- one and only NaN. Having no significand, it has no zero and no subnormals either:
+-- with nothing for the E=0 encoding to mean, it simply denotes 2^-127.
+e8m0Bias :: Int
+e8m0Bias = 127
+
+-- | The value a stored E8M0 exponent denotes. All 254 finite values are exactly
+-- representable as a Double, since 2^(+/-127) is nowhere near its range limits; note
+-- that 'encodeFloat' builds them exactly, which @2 **@ would not be guaranteed to do.
+e8m0Value :: Int -> Double
+e8m0Value 255 = 0/0
+e8m0Value e   = encodeFloat 1 (e - e8m0Bias)
+
+-- | Lay out an E8M0 value. With no sign and no significand there is no IEEE look-alike
+-- to lean on, so the layout is built by hand, following the shape crackNum prints for
+-- the other formats. Everything from the classification down describes the value rather
+-- than its layout, so that part comes from cracking the equivalent Double -- the same
+-- division of labor 'modOut' uses for the E4M3 and FP4 deviations.
+e8m0Layout :: Bool -> String -> Int -> [String]
+e8m0Layout debug tag stored =
+     [ "Satisfiable. Model:"
+     , "  " ++ tag ++ " = " ++ show v ++ " :: " ++ show E8M0
+     , "                  76543210"
+     , "                  ---E8---"
+     , "   Binary layout: " ++ pad 8 (inBase 2 stored)
+     , "      Hex layout: " ++ map toUpper (pad 2 (inBase 16 stored))
+     , "       Precision: 8 exponent bits, no significand"
+     -- NB. There is no sign bit: bit 7 is the exponent's MSB. We print the line anyway,
+     -- so the block keeps the same shape as every other format, but say outright that
+     -- it can never read anything else.
+     , "            Sign: Positive (always)"
+     , "        Exponent: " ++ show (stored - e8m0Bias) ++ " (Stored: " ++ show stored ++ ", Bias: " ++ show e8m0Bias ++ ")"
+     ]
+  ++ dropNaNUniquenessNote (dropWhile (not . isClassification) (lines (SBV.crack debug (literal v :: SDouble))))
+  where v = e8m0Value stored
+
+        inBase b x = showIntAtBase b intToDigit x ""
+
+        pad n x = replicate (n - length x) '0' ++ x
+
+-- | Decoding E8M0: the entire byte is the stored exponent.
+decodeE8M0 :: Bool -> [Bool] -> IO ()
+decodeE8M0 debug bs@[_, _, _, _, _, _, _, _] = putStr $ unlines $ e8m0Layout debug "DECODED" (foldl (\sofar b -> 2 * sofar + (if b then 1 else 0)) 0 bs)
+decodeE8M0 _     bs                          = error $ "decodeE8M0: Unexpected bits: " ++ show bs   -- Can't happen; the caller checks the width
+
+-- | Encoding E8M0. The representable values are the powers of two from 2^-127 to 2^127,
+-- plus NaN, so we round the exponent by hand. Rounding is always between two adjacent
+-- powers of two; we split them at the arithmetic midpoint (1.5 * 2^e, not the geometric
+-- one) and break RNE ties toward the even /stored/ exponent. Both follow 'encodeFP4',
+-- which ties on the parity of the encoding index rather than of the value's exponent.
+encodeE8M0 :: Bool -> RM -> String -> IO ()
+encodeE8M0 debug rm inp = case reads (fixup True inp) of
+                            [(v :: Double, "")] -> analyze v
+                            _                   -> -- maybe it's a hexfloat? As in encodeFP4, the catch must
+                                                   -- scope over the parse only: analyze can legitimately die,
+                                                   -- and die throws an exit-exception of its own.
+                                                   do let hr = readHexRational inp
+                                                      ok <- (rnf hr `seq` pure True)
+                                                              `C.catch` (\(_ :: C.SomeException) -> pure False)
+                                                      if ok then analyze (fromRational hr)
+                                                            else unrecognized inp
+ where smallest, largest :: Double
+       smallest = e8m0Value 0
+       largest  = e8m0Value 254
+
+       analyze :: Double -> IO ()
+       analyze v
+         -- NaN is representable, and uniquely so.
+         | isNaN v
+         = out 255
+         -- A negative is not an out-of-range magnitude: with no sign bit there is no
+         -- direction to saturate towards, and clamping would quietly make it positive.
+         | v < 0 || isNegativeZero v
+         = die [ "E8M0 has no representation for negative values."
+               , "The representable range is [2^-127, 2^127], plus NaN."
+               ]
+         -- Infinity is the limiting overflow, so it saturates along with anything else
+         -- that is too large.
+         | isInfinite v || v > largest
+         = out 254
+         -- The bottom of the range is a hard cliff: there is no zero and no subnormal
+         -- below 2^-127, so zero and everything under it saturates up to it.
+         | v < smallest
+         = out 0
+         | True
+         = out (e8m0Bias + roundExp v)
+        where out stored = do putStr $ unlines $ e8m0Layout debug "ENCODED" stored
+                              trailer v stored
+
+       -- The exponent we land on, for a v already known to be in range. 'exponent'
+       -- returns the e with v = m * 2^e and 0.5 <= m < 1, so lo is the exponent whose
+       -- power of two sits at or just below v.
+       roundExp :: Double -> Int
+       roundExp v
+         | v == twoTo lo    -- Exactly representable
+         = lo
+         | True
+         = case rm of
+             RTZ -> lo      -- Every value is positive, so RTZ and RTN necessarily agree
+             RTN -> lo
+             RTP -> hi
+             RNE -> nearest (if even (lo + e8m0Bias) then lo else hi)
+             RNA -> nearest hi
+        where lo = exponent v - 1
+              hi = lo + 1
+
+              twoTo :: Int -> Double
+              twoTo = encodeFloat 1
+
+              -- Ties are broken by the given choice; note that comparing against the sum
+              -- avoids any rounding of its own, since 2*v and 3*2^lo are both exact here.
+              nearest tie = case compare (2 * v) (twoTo lo + twoTo hi) of
+                              LT -> lo
+                              GT -> hi
+                              EQ -> tie
+
+       trailer :: Double -> Int -> IO ()
+       trailer v stored = do putStrLn $ "   Rounding mode: " ++ show rm
+                             note
+         where t = e8m0Value stored
+
+               note
+                 | isNaN v
+                 = exact
+                 | isInfinite v || v > largest || v < smallest
+                 = do putStrLn $ "            Note: Original value of " ++ show v ++ " is out of range, saturated to " ++ show t ++ "."
+                      putStrLn   "                  The representable range is [2^-127, 2^127]."
+                 | v == t
+                 = exact
+                 | True
+                 = putStrLn $ "            Note: Original value of " ++ show v ++ " was rounded to " ++ show t ++ "."
+
+               exact = putStrLn $ "            Note: Conversion from " ++ show inp ++ " was exact. No rounding happened."
diff --git a/src/CrackNum/TestSuite.hs b/src/CrackNum/TestSuite.hs
--- a/src/CrackNum/TestSuite.hs
+++ b/src/CrackNum/TestSuite.hs
@@ -145,6 +145,31 @@
             | rm           <- ["RNE", "RNA", "RTP", "RTN", "RTZ"]
             ,  i :: Double <- [0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 8]
             ]
+          , testGroup "EncodeE8M0" [
+               gold "encodeE8M0_nan"   "-fe8m0    nan"     -- Representable, and uniquely so
+             , gold "encodeE8M0_+inf"  "-fe8m0    inf"     -- The limiting overflow; saturates
+             , gold "encodeE8M0_-inf"  "-fe8m0 -- -inf"    -- Negative: rejected, not saturated
+             , gold "encodeE8M0_neg"   "-fe8m0 -- -5"
+             , gold "encodeE8M0_zero1" "-fe8m0 --  0"      -- No zero in the format; saturates up to 2^-127
+             , gold "encodeE8M0_zero2" "-fe8m0 --  -0"     -- But a negative zero is still negative
+             , gold "encodeE8M0_one"   "-fe8m0 --  1"
+             , gold "encodeE8M0_exact" "-fe8m0 --  0.25"
+             , gold "encodeE8M0_min"   "-fe8m0 --  0x1p-127"
+             , gold "encodeE8M0_max"   "-fe8m0 --  0x1p+127"
+             , gold "encodeE8M0_oob1"  "-fe8m0 --  1e40"   -- Saturates
+             , gold "encodeE8M0_oob2"  "-fe8m0 --  1e-40"
+             , gold "encodeE8M0_hex"   "-fe8m0 --  0x1.8p1"
+            ]
+          -- Every value that sits exactly half-way between two representable powers of
+          -- two, over all rounding modes. Note that 1.5 and 3 are what pin the RNE tie
+          -- rule down: they straddle stored exponents of opposite parity, so reading
+          -- "ties to even" as the unbiased exponent rather than the stored one would
+          -- send them the other way. All values are positive; negatives are rejected.
+          , testGroup "EncodeE8M0Ties" [
+               gold ("encodeE8M0_tie_" ++ rm ++ "_+" ++ show i) ("-fe8m0 -r" ++ rm ++ " --  " ++ show i)
+            | rm           <- ["RNE", "RNA", "RTP", "RTN", "RTZ"]
+            ,  i :: Double <- [0.75, 1.5, 3, 6]
+            ]
           , testGroup "Decode" [
               gold "decode0" "-i4       0b0110"
             , gold "decode1" "-w4       0xE"
@@ -201,6 +226,19 @@
             | s <- ["0", "1"]
             , m <- ["000", "001", "010", "011", "100", "101", "110", "111"]
             , let bits = s ++ m
+            ]
+          -- E8M0 is all exponent, so decoding is a table lookup; a spread of patterns
+          -- covering both ends, the unit value, and the sole NaN is enough.
+          , testGroup "DecodeE8M0" [
+               gold ("decodeE8M0_" ++ bits) ("-fe8m0 0x" ++ bits)
+            | bits <- [ "00"     -- Smallest: 2^-127. Not zero: the format has none
+                      , "01"
+                      , "7F"     -- 1.0
+                      , "80"
+                      , "FD"
+                      , "FE"     -- Largest: 2^127
+                      , "FF"     -- NaN, and the only one
+                      ]
             ]
           , testGroup "Bad" [
                gold "badInvocation0" "-f3+4 0b01"
