[aes/rtl] Remove X assignments, add SVAs for selector signals

This commit replaces all X assignments in the AES RTL with defined
values. In addition, SystemVerilog Assertions are added to catch
invalid signal values in simulation.

This is related to lowRISC/opentitan#366.

Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv
index a05acdb..48d569f 100644
--- a/hw/ip/aes/rtl/aes_control.sv
+++ b/hw/ip/aes/rtl/aes_control.sv
@@ -215,10 +215,10 @@
                 unique case (mode_i)
                   AES_ENC: key_words_sel_o = KEY_WORDS_0123;
                   AES_DEC: key_words_sel_o = KEY_WORDS_2345;
-                  default: key_words_sel_o = key_words_sel_e'(1'bX);
+                  default: key_words_sel_o = KEY_WORDS_ZERO;
                 endcase
               end else begin
-                key_words_sel_o = key_words_sel_e'(1'bX);
+                key_words_sel_o = KEY_WORDS_ZERO;
               end
             end
 
@@ -226,11 +226,11 @@
               unique case (mode_i)
                 AES_ENC:   key_words_sel_o = KEY_WORDS_0123;
                 AES_DEC:   key_words_sel_o = KEY_WORDS_4567;
-                default:   key_words_sel_o = key_words_sel_e'(1'bX);
+                default:   key_words_sel_o = KEY_WORDS_ZERO;
               endcase
             end
 
-            default: key_words_sel_o = key_words_sel_e'(1'bX);
+            default: key_words_sel_o = KEY_WORDS_ZERO;
           endcase
         end
 
@@ -263,10 +263,10 @@
                 unique case (mode_i)
                   AES_ENC: key_words_sel_o = KEY_WORDS_2345;
                   AES_DEC: key_words_sel_o = KEY_WORDS_0123;
-                  default: key_words_sel_o = key_words_sel_e'(1'bX);
+                  default: key_words_sel_o = KEY_WORDS_ZERO;
                 endcase
               end else begin
-                key_words_sel_o = key_words_sel_e'(1'bX);
+                key_words_sel_o = KEY_WORDS_ZERO;
               end
             end
 
@@ -274,11 +274,11 @@
               unique case (mode_i)
                 AES_ENC:   key_words_sel_o = KEY_WORDS_4567;
                 AES_DEC:   key_words_sel_o = KEY_WORDS_0123;
-                default:   key_words_sel_o = key_words_sel_e'(1'bX);
+                default:   key_words_sel_o = KEY_WORDS_ZERO;
               endcase
             end
 
-            default: key_words_sel_o = key_words_sel_e'(1'bX);
+            default: key_words_sel_o = KEY_WORDS_ZERO;
           endcase
         end
 
@@ -320,10 +320,10 @@
                 unique case (mode_i)
                   AES_ENC: key_words_sel_o = KEY_WORDS_2345;
                   AES_DEC: key_words_sel_o = KEY_WORDS_0123;
-                  default: key_words_sel_o = key_words_sel_e'(1'bX);
+                  default: key_words_sel_o = KEY_WORDS_ZERO;
                 endcase
               end else begin
-                key_words_sel_o = key_words_sel_e'(1'bX);
+                key_words_sel_o = KEY_WORDS_ZERO;
               end
             end
 
@@ -331,11 +331,11 @@
               unique case (mode_i)
                 AES_ENC:   key_words_sel_o = KEY_WORDS_4567;
                 AES_DEC:   key_words_sel_o = KEY_WORDS_0123;
-                default:   key_words_sel_o = key_words_sel_e'(1'bX);
+                default:   key_words_sel_o = KEY_WORDS_ZERO;
               endcase
             end
 
-            default: key_words_sel_o = key_words_sel_e'(1'bX);
+            default: key_words_sel_o = KEY_WORDS_ZERO;
           endcase
         end
 
@@ -381,7 +381,7 @@
         aes_ctrl_ns = IDLE;
       end
 
-      default: aes_ctrl_ns = aes_ctrl_e'(1'bX);
+      default: aes_ctrl_ns = IDLE;
     endcase
   end
 
@@ -451,4 +451,19 @@
   assign data_in_clear_o     = 1'b0;
   assign data_out_clear_o    = 1'b0;
 
+  // Selectors must be known/valid
+  `ASSERT_KNOWN(AesModeKnown, mode_i, clk_i, !rst_ni)
+  `ASSERT(AesKeyLenValid, key_len_i inside {
+      AES_128,
+      AES_192,
+      AES_256
+      }, clk_i, !rst_ni)
+  `ASSERT(AesControlStateValid, aes_ctrl_cs inside {
+      IDLE,
+      INIT,
+      ROUND,
+      FINISH,
+      CLEAR
+      }, clk_i, !rst_ni)
+
 endmodule
diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv
index b4afff3..148e7a0 100644
--- a/hw/ip/aes/rtl/aes_core.sv
+++ b/hw/ip/aes/rtl/aes_core.sv
@@ -133,7 +133,7 @@
       STATE_INIT:  state_d = state_init;
       STATE_ROUND: state_d = add_round_key_out;
       STATE_CLEAR: state_d = '0;
-      default:     state_d = 'X;
+      default:     state_d = state_init;
     endcase
   end
 
@@ -169,7 +169,7 @@
       ADD_RK_INIT:  add_round_key_in = state_q;
       ADD_RK_ROUND: add_round_key_in = mix_columns_out;
       ADD_RK_FINAL: add_round_key_in = shift_rows_out;
-      default:      add_round_key_in = 'X;
+      default:      add_round_key_in = state_q;
     endcase
   end
 
@@ -184,7 +184,7 @@
     unique case (key_init_sel)
       KEY_INIT_INPUT: key_init_d = key_init;
       KEY_INIT_CLEAR: key_init_d = '0;
-      default:        key_init_d = 'X;
+      default:        key_init_d = key_init;
     endcase
   end
 
@@ -207,7 +207,7 @@
       KEY_FULL_DEC_INIT: key_full_d = key_dec_q;
       KEY_FULL_ROUND:    key_full_d = key_expand_out;
       KEY_FULL_CLEAR:    key_full_d = '0;
-      default:           key_full_d = 'X;
+      default:           key_full_d = key_init_q;
     endcase
   end
 
@@ -224,7 +224,7 @@
     unique case (key_dec_sel)
       KEY_DEC_EXPAND: key_dec_d = key_expand_out;
       KEY_DEC_CLEAR:  key_dec_d = '0;
-      default:        key_dec_d = 'X;
+      default:        key_dec_d = key_expand_out;
     endcase
   end
 
@@ -254,10 +254,10 @@
   always_comb begin : key_words_mux
     unique case (key_words_sel)
       KEY_WORDS_0123: key_words = key_full_q[3:0];
-      KEY_WORDS_2345: key_words = AES192Enable ? key_full_q[5:2] : 'X;
+      KEY_WORDS_2345: key_words = AES192Enable ? key_full_q[5:2] : key_full_q[3:0];
       KEY_WORDS_4567: key_words = key_full_q[7:4];
       KEY_WORDS_ZERO: key_words = '0;
-      default:        key_words = 'X;
+      default:        key_words = key_full_q[3:0];
     endcase
   end
 
@@ -274,7 +274,7 @@
     unique case (round_key_sel)
       ROUND_KEY_DIRECT: round_key = key_bytes;
       ROUND_KEY_MIXED:  round_key = key_mix_columns_out;
-      default:          round_key = 'X;
+      default:          round_key = key_bytes;
     endcase
   end
 
@@ -396,4 +396,31 @@
 
   assign hw2reg.ctrl.key_len.d  = {key_len_q};
 
+  ////////////////
+  // Assertions //
+  ////////////////
+
+  // Selectors must be known/valid
+  `ASSERT_KNOWN(AesModeKnown, mode_q, clk_i, !rst_ni)
+  `ASSERT(AesKeyLenValid, key_len_q inside {
+      AES_128,
+      AES_192,
+      AES_256
+      }, clk_i, !rst_ni)
+  `ASSERT(AesStateSelValid, state_sel inside {
+      STATE_INIT,
+      STATE_ROUND,
+      STATE_CLEAR
+      }, clk_i, !rst_ni)
+  `ASSERT(AesAddRKSelValid, add_round_key_in_sel inside {
+      ADD_RK_INIT,
+      ADD_RK_ROUND,
+      ADD_RK_FINAL
+      }, clk_i, !rst_ni)
+  `ASSERT_KNOWN(AesKeyInitSelKnown, key_init_sel, clk_i, !rst_ni)
+  `ASSERT_KNOWN(AesKeyFullSelKnown, key_full_sel, clk_i, !rst_ni)
+  `ASSERT_KNOWN(AesKeyDecSelKnown, key_dec_sel, clk_i, !rst_ni)
+  `ASSERT_KNOWN(AesKeyWordsSelKnown, key_words_sel, clk_i, !rst_ni)
+  `ASSERT_KNOWN(AesRoundKeySelKnown, round_key_sel, clk_i, !rst_ni)
+
 endmodule
diff --git a/hw/ip/aes/rtl/aes_key_expand.sv b/hw/ip/aes/rtl/aes_key_expand.sv
index 0728b15..d15ea42 100644
--- a/hw/ip/aes/rtl/aes_key_expand.sv
+++ b/hw/ip/aes/rtl/aes_key_expand.sv
@@ -83,10 +83,10 @@
       rcon_d =  (mode_i == AES_ENC)                            ? 8'h01 :
                ((mode_i == AES_DEC) && (key_len_i == AES_128)) ? 8'h36 :
                ((mode_i == AES_DEC) && (key_len_i == AES_192)) ? 8'h80 :
-               ((mode_i == AES_DEC) && (key_len_i == AES_256)) ? 8'h40 : 8'hXX;
+               ((mode_i == AES_DEC) && (key_len_i == AES_256)) ? 8'h40 : 8'h01;
     end else begin
       rcon_d =  (mode_i == AES_ENC) ? aes_mul2(rcon_q) :
-                (mode_i == AES_DEC) ? aes_div2(rcon_q) : 8'hXX;
+                (mode_i == AES_DEC) ? aes_div2(rcon_q) : 8'h01;
     end
   end
 
@@ -116,7 +116,7 @@
         unique case (mode_i)
           AES_ENC: rot_word_in = key_i[3];
           AES_DEC: rot_word_in = spec_in_128;
-          default: rot_word_in = 'X;
+          default: rot_word_in = key_i[3];
         endcase
       end
 
@@ -129,16 +129,16 @@
             AES_ENC: begin
               rot_word_in = rnd_type[0] ? key_i[5]    :
                             rnd_type[2] ? key_i[5]    :
-                            rnd_type[3] ? spec_in_192 : 'X;
+                            rnd_type[3] ? spec_in_192 : key_i[3];
             end
             AES_DEC: begin
               rot_word_in = rnd_type[1] ? key_i[3] :
-                            rnd_type[2] ? key_i[1] : 'X;
+                            rnd_type[2] ? key_i[1] : key_i[3];
             end
-            default: rot_word_in = 'X;
+            default: rot_word_in = key_i[3];
           endcase
         end else begin
-          rot_word_in = 'X;
+          rot_word_in = key_i[3];
         end
       end
 
@@ -149,11 +149,11 @@
         unique case (mode_i)
           AES_ENC: rot_word_in = key_i[7];
           AES_DEC: rot_word_in = key_i[3];
-          default: rot_word_in = 'X;
+          default: rot_word_in = key_i[7];
         endcase
       end
 
-      default: rot_word_in = 'X;
+      default: rot_word_in = key_i[3];
     endcase
   end
 
@@ -183,6 +183,9 @@
   ///////////////////////////
   // The more regular part //
   ///////////////////////////
+
+  // To reduce muxing resources, we re-use existing
+  // connections for unused words and default cases.
   always_comb begin : drive_regular
     unique case (key_len_i)
 
@@ -191,7 +194,7 @@
       /////////////
       AES_128: begin
         // key_o[7:4] not used
-        regular[7:4] = 'X;
+        regular[7:4] = key_i[3:0];
 
         regular[0] = irregular ^ key_i[0];
         unique case (mode_i)
@@ -207,7 +210,7 @@
             end
           end
 
-          default: regular = 'X;
+          default: regular = {key_i[3:0], key_i[7:4]};
         endcase
       end
 
@@ -216,7 +219,7 @@
       /////////////
       AES_192: begin
         // key_o[7:6] not used
-        regular[7:6] = 'X;
+        regular[7:6] = key_i[3:2];
 
         if (AES192Enable) begin
           unique case (mode_i)
@@ -265,11 +268,11 @@
               end // rnd_type[0]
             end
 
-            default: regular = 'X;
+            default: regular = {key_i[3:0], key_i[7:4]};
           endcase
 
         end else begin
-          regular = 'X;
+          regular = {key_i[3:0], key_i[7:4]};
         end // AES192Enable
       end
 
@@ -281,7 +284,8 @@
           AES_ENC: begin
             if (rnd == 0) begin
               // Round 0: Nothing to be done
-              regular = key_i;
+              // The Full Key registers are not updated
+              regular = {key_i[3:0], key_i[7:4]};
             end else begin
               // Shift down old upper half
               regular[3:0] = key_i[7:4];
@@ -296,7 +300,8 @@
           AES_DEC: begin
             if (rnd == 0) begin
               // Round 0: Nothing to be done
-              regular = key_i;
+              // The Full Key registers are not updated
+              regular = {key_i[3:0], key_i[7:4]};
             end else begin
               // Shift up old lower half
               regular[7:4] = key_i[3:0];
@@ -308,15 +313,23 @@
             end // rnd == 0
           end
 
-          default: regular = 'X;
+          default: regular = {key_i[3:0], key_i[7:4]};
         endcase
       end
 
-      default: regular = 'X;
+      default: regular = {key_i[3:0], key_i[7:4]};
     endcase // key_len_i
   end
 
   // Drive output
   assign key_o = regular;
 
+  // Selectors must be known/valid
+  `ASSERT_KNOWN(AesModeKnown, mode_i, clk_i, !rst_ni)
+  `ASSERT(AesKeyLenValid, key_len_i inside {
+      AES_128,
+      AES_192,
+      AES_256
+      }, clk_i, !rst_ni)
+
 endmodule