diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS
index 13308d1cc..3f5d53095 100644
--- a/docs/CONTRIBUTORS
+++ b/docs/CONTRIBUTORS
@@ -31,6 +31,7 @@ Harald Heckmann
 Howard Su
 Huang Rui
 HyungKi Jeong
+Iru Cai
 Ivan Vnučec
 Iztok Jeras
 James Hanlon
diff --git a/src/V3Number.cpp b/src/V3Number.cpp
index 595830d27..e4ea84f22 100644
--- a/src/V3Number.cpp
+++ b/src/V3Number.cpp
@@ -605,6 +605,24 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
             while (bit && bitIs0(bit)) bit--;
         while ((bit % 3) != 2) bit++;
         for (; bit > 0; bit -= 3) {
+            const int numX = countX(bit - 2, 3);
+            const int numZ = countZ(bit - 2, 3);
+            if (numX == 3 || numX == width() - (bit - 2)) {
+                str += 'x';
+                continue;
+            }
+            if (numZ == 3 || numZ == width() - (bit - 2)) {
+                str += 'z';
+                continue;
+            }
+            if (numX > 0) {
+                str += 'X';
+                continue;
+            }
+            if (numZ > 0) {
+                str += 'Z';
+                continue;
+            }
             int v = bitsValue(bit - 2, 3);
             str += static_cast<char>('0' + v);
         }
@@ -617,6 +635,24 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
             while (bit && bitIs0(bit)) bit--;
         while ((bit % 4) != 3) bit++;
         for (; bit > 0; bit -= 4) {
+            const int numX = countX(bit - 3, 4);
+            const int numZ = countZ(bit - 3, 4);
+            if (numX == 4 || numX == width() - (bit - 3)) {
+                str += 'x';
+                continue;
+            }
+            if (numZ == 4 || numZ == width() - (bit - 3)) {
+                str += 'z';
+                continue;
+            }
+            if (numX > 0) {
+                str += 'X';
+                continue;
+            }
+            if (numZ > 0) {
+                str += 'Z';
+                continue;
+            }
             int v = bitsValue(bit - 3, 4);
             if (v >= 10) {
                 str += static_cast<char>('a' + v - 10);
@@ -667,17 +703,33 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
             if (issigned) dchars++;  // space for sign
             fmtsize = cvtToStr(int(dchars));
         }
-        if (issigned) {
-            if (width() > 64) {
-                str = toDecimalS();
+        bool hasXZ = false;
+        if (isAllX()) {
+            str = "x";
+            hasXZ = true;
+        } else if (isAllZ()) {
+            str = "z";
+            hasXZ = true;
+        } else if (isAnyX()) {
+            str = "X";
+            hasXZ = true;
+        } else if (isAnyZ()) {
+            str = "Z";
+            hasXZ = true;
+        }
+        if (!hasXZ) {
+            if (issigned) {
+                if (width() > 64) {
+                    str = toDecimalS();
+                } else {
+                    str = cvtToStr(toSQuad());
+                }
             } else {
-                str = cvtToStr(toSQuad());
-            }
-        } else {
-            if (width() > 64) {
-                str = toDecimalU();
-            } else {
-                str = cvtToStr(toUQuad());
+                if (width() > 64) {
+                    str = toDecimalU();
+                } else {
+                    str = cvtToStr(toUQuad());
+                }
             }
         }
         const bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0';
@@ -977,6 +1029,22 @@ bool V3Number::isLtXZ(const V3Number& rhs) const {
     }
     return false;
 }
+int V3Number::countX(int lsb, int nbits) const {
+    int count = 0;
+    for (int bitn = 0; bitn < nbits; ++bitn) {
+        if (lsb + bitn >= width()) return count;
+        if (bitIsX(lsb + bitn)) ++count;
+    }
+    return count;
+}
+int V3Number::countZ(int lsb, int nbits) const {
+    int count = 0;
+    for (int bitn = 0; bitn < nbits; ++bitn) {
+        if (lsb + bitn >= width()) return count;
+        if (bitIsZ(lsb + bitn)) ++count;
+    }
+    return count;
+}
 
 int V3Number::widthMin() const {
     for (int bit = width() - 1; bit > 0; bit--) {
diff --git a/src/V3Number.h b/src/V3Number.h
index 09b15e67b..9a33a6b7a 100644
--- a/src/V3Number.h
+++ b/src/V3Number.h
@@ -204,6 +204,9 @@ private:
         return v;
     }
 
+    int countX(int lsb, int nbits) const;
+    int countZ(int lsb, int nbits) const;
+
     int words() const { return ((width() + 31) / 32); }
     uint32_t hiWordMask() const { return VL_MASK_I(width()); }
 
diff --git a/test_regress/t/t_display.out b/test_regress/t/t_display.out
index 9b2b995ce..0475a1952 100644
--- a/test_regress/t/t_display.out
+++ b/test_regress/t/t_display.out
@@ -74,4 +74,12 @@ multiline
 '    beep'
 'beep    '
 log10(2) =                    2
+x
+xxXa
+XXX 1x5X
+         x
+         z
+         X
+         Z
+ZzX
 *-* All Finished *-*
diff --git a/test_regress/t/t_display.v b/test_regress/t/t_display.v
index 073268617..3f191f9b1 100644
--- a/test_regress/t/t_display.v
+++ b/test_regress/t/t_display.v
@@ -179,6 +179,16 @@ multiline", $time);
       $display("log10(2) = %d", $log10(100));
       // verilator lint_on REALCVT
 
+      // unknown and high-impedance values
+      $display("%d", 1'bx);
+      $display("%h", 14'bx01010);
+      $display("%h %o", 12'b001xxx101x01, 12'b001xxx101x01);
+      $display("%d", 32'bx);
+      $display("%d", 32'bz);
+      $display("%d", 32'b11x11z111);
+      $display("%d", 32'b11111z111);
+      $display("%h", 12'b1zz1_zzzz_1x1z);
+
       $write("*-* All Finished *-*\n");
       $finish;
    end