[aes] Add muxes + skeletons for data path and control modules

This commit adds the muxes and skeletons for the different modules of
the cipher and key expand data paths as well as of the control module.
The modules themselves are still empty.
diff --git a/hw/ip/aes/aes.core b/hw/ip/aes/aes.core
index 3725b26..a81b155 100644
--- a/hw/ip/aes/aes.core
+++ b/hw/ip/aes/aes.core
@@ -14,6 +14,11 @@
       - rtl/aes_reg_pkg.sv
       - rtl/aes_reg_top.sv
       - rtl/aes_core.sv
+      - rtl/aes_sub_bytes.sv
+      - rtl/aes_shift_rows.sv
+      - rtl/aes_mix_columns.sv
+      - rtl/aes_key_expand.sv
+      - rtl/aes_control.sv
       - rtl/aes.sv
     file_type: systemVerilogSource
 
diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv
new file mode 100644
index 0000000..4377446
--- /dev/null
+++ b/hw/ip/aes/rtl/aes_control.sv
@@ -0,0 +1,137 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// AES control
+
+module aes_control #(
+  parameter bit AES192Enable = 1
+) (
+  input  logic                    clk_i,
+  input  logic                    rst_ni,
+
+  // Main control inputs
+  input  aes_pkg::mode_e          mode_i,
+  input  aes_pkg::key_len_e       key_len_i,
+  input  logic                    force_data_overwrite_i,
+  input  logic                    manual_start_trigger_i,
+  input  logic                    start_i,
+
+  // I/O register read/write enables
+  input  logic [3:0]              data_in_qe_i,
+  input  logic [7:0]              key_init_qe_i,
+  input  logic [3:0]              data_out_re_i,
+
+  // Control ouptuts cipher data path
+  output aes_pkg::state_sel_e     state_sel_o,
+  output logic                    state_we_o,
+  output aes_pkg::add_rk_sel_e    add_rk_sel_o,
+
+  // Control outputs key expand data path
+  output aes_pkg::key_full_sel_e  key_full_sel_o,
+  output logic                    key_full_we_o,
+  output aes_pkg::key_dec_sel_e   key_dec_sel_o,
+  output logic                    key_dec_we_o,
+  output logic                    key_expand_clear_o,
+  output aes_pkg::key_words_sel_e key_words_sel_o,
+
+  // Output registers control
+  output logic                    data_out_we_o,
+
+  // To I/O registers
+  output logic                    trigger_o,
+  output logic                    trigger_we_o,
+  output logic                    output_valid_o,
+  output logic                    output_valid_we_o,
+  output logic                    input_ready_o,
+  output logic                    input_ready_we_o,
+  output logic                    idle_o,
+  output logic                    idle_we_o,
+  output logic                    stall_o,
+  output logic                    stall_we_o
+);
+
+  import aes_pkg::*;
+
+  // Signals
+  logic [3:0] data_in_new_d, data_in_new_q;
+  logic       data_in_new;
+  logic       data_in_load;
+
+  logic [7:0] key_init_new_d, key_init_new_q;
+  logic       key_init_new;
+  logic       dec_key_gen;
+
+  logic [3:0] data_out_read_d, data_out_read_q;
+  logic       data_out_read;
+
+  assign data_in_load = (state_sel_o == STATE_INIT);
+
+  // Placeholders
+  mode_e    unused_mode;
+  key_len_e unused_key_len;
+  logic     unused_force_data_overwrite;
+  logic     unused_manual_start_trigger;
+  logic     unused_start;
+  logic     unused_key_init_new;
+  assign    unused_mode                 = mode_i;
+  assign    unused_key_len              = key_len_i;
+  assign    unused_force_data_overwrite = force_data_overwrite_i;
+  assign    unused_manual_start_trigger = manual_start_trigger_i;
+  assign    unused_start                = start_i;
+  assign    unused_key_init_new  = key_init_new;
+
+  assign state_sel_o        = STATE_ROUND;
+  assign state_we_o         = 1'b0;
+  assign add_rk_sel_o       = ADD_RK_ROUND;
+
+  assign key_full_sel_o     = KEY_FULL_ROUND;
+  assign key_full_we_o      = 1'b0;
+  assign key_dec_sel_o      = KEY_DEC_EXPAND;
+  assign key_dec_we_o       = 1'b0;
+  assign key_expand_clear_o = 1'b0;
+  assign key_words_sel_o    = KEY_WORDS_0123;
+
+  assign dec_key_gen   = 1'b0;
+
+  assign data_out_we_o = 1'b0;
+
+  assign trigger_o     = 1'b0;
+  assign trigger_we_o  = 1'b1;
+  assign idle_o        = 1'b0;
+  assign idle_we_o     = 1'b1;
+  assign stall_o       = 1'b0;
+  assign stall_we_o    = 1'b1;
+
+  // Detect new key, new input, output read
+  // Edge detectors are cleared by the FSM
+  assign key_init_new_d = dec_key_gen ? '0 : key_init_new_q | key_init_qe_i;
+  assign key_init_new   = &key_init_new_d;
+
+  assign data_in_new_d = data_in_load ? '0 : data_in_new_q | data_in_qe_i;
+  assign data_in_new   = &data_in_new_d;
+
+  assign data_out_read_d = data_out_we_o ? '0 : data_out_read_q | data_out_re_i;
+  assign data_out_read   = &data_out_read_d;
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin : reg_edge_detection
+    if (!rst_ni) begin
+      key_init_new_q  <= '0;
+      data_in_new_q   <= '0;
+      data_out_read_q <= '0;
+    end else begin
+      key_init_new_q  <= key_init_new_d;
+      data_in_new_q   <= data_in_new_d;
+      data_out_read_q <= data_out_read_d;
+    end
+  end
+
+  // clear once all output regs have been read
+  assign output_valid_o    = data_out_we_o;
+  assign output_valid_we_o = data_out_we_o | data_out_read;
+
+  // clear once all input regs have been written
+  assign input_ready_o     = ~data_in_new;
+  assign input_ready_we_o  =  data_in_new | data_in_load;
+
+endmodule
diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv
index f62eb37..50c628e 100644
--- a/hw/ip/aes/rtl/aes_core.sv
+++ b/hw/ip/aes/rtl/aes_core.sv
@@ -18,37 +18,51 @@
   import aes_reg_pkg::*;
   import aes_pkg::*;
 
-  // Types
-
   // Signals
-  logic [31:0] data_in[4];
-  logic  [3:0] data_in_new_d, data_in_new_q;
-  logic        data_in_new;
-  logic        data_in_load;
+  logic    [31:0] data_in[4];
+  logic     [3:0] data_in_qe;
+  logic    [31:0] key_init[8];
+  logic     [7:0] key_init_qe;
 
-  logic [31:0] key_init[8];
-  logic  [7:0] key_init_new_d, key_init_new_q;
-  logic        key_init_new;
-  logic        dec_key_gen;
+  mode_e          mode;
+  key_len_e       key_len;
 
-  logic        force_data_overwrite;
-  logic        manual_start_trigger;
-  key_len_e    key_len;
-  mode_e       mode;
-  logic        start;
+  logic     [7:0] state_init[16];
+  logic     [7:0] state_d[16];
+  logic     [7:0] state_q[16];
+  logic           state_we;
+  state_sel_e     state_sel;
 
-  logic [7:0]  state_init[16];
-  logic [7:0]  state_d[16];
-  logic [7:0]  state_q[16];
+  logic     [7:0] sub_bytes_out[16];
+  logic     [7:0] shift_rows_out[16];
+  logic     [7:0] mix_columns_out[16];
+  logic     [7:0] add_round_key_in[16];
+  logic     [7:0] add_round_key_out[16];
+  add_rk_sel_e    add_round_key_in_sel;
 
-  logic [31:0] data_out_d[4];
-  logic [31:0] data_out_q[4];
-  logic        data_out_we;
-  logic  [3:0] data_out_read_d, data_out_read_q;
-  logic        data_out_read;
+  logic    [31:0] key_full_d[8];
+  logic    [31:0] key_full_q[8];
+  logic           key_full_we;
+  key_full_sel_e  key_full_sel;
+  logic    [31:0] key_dec_d[8];
+  logic    [31:0] key_dec_q[8];
+  logic           key_dec_we;
+  key_dec_sel_e   key_dec_sel;
+  logic    [31:0] key_expand_out[8];
+  logic           key_expand_clear;
+  key_words_sel_e key_words_sel;
+  logic    [31:0] key_words[4];
+  logic     [7:0] key_bytes[16];
+  logic     [7:0] key_mix_columns_out[16];
+  logic     [7:0] round_key[16];
+
+  logic    [31:0] data_out_d[4];
+  logic    [31:0] data_out_q[4];
+  logic           data_out_we;
+  logic     [3:0] data_out_re;
 
   // Unused signals
-  logic [31:0] unused_data_out_q[4];
+  logic    [31:0] unused_data_out_q[4];
 
   // Inputs
   assign key_init[0] = reg2hw.key0.q;
@@ -60,11 +74,17 @@
   assign key_init[6] = reg2hw.key6.q;
   assign key_init[7] = reg2hw.key7.q;
 
+  assign key_init_qe = {reg2hw.key7.qe, reg2hw.key6.qe, reg2hw.key5.qe, reg2hw.key4.qe,
+                        reg2hw.key3.qe, reg2hw.key2.qe, reg2hw.key1.qe, reg2hw.key0.qe};
+
   assign data_in[0] = reg2hw.data_in0.q;
   assign data_in[1] = reg2hw.data_in1.q;
   assign data_in[2] = reg2hw.data_in2.q;
   assign data_in[3] = reg2hw.data_in3.q;
 
+  assign data_in_qe = {reg2hw.data_in3.qe, reg2hw.data_in2.qe,
+                       reg2hw.data_in1.qe, reg2hw.data_in0.qe};
+
   always_comb begin : conv_data_in_to_state
     for (int i=0; i<4; i++) begin
       state_init[4*i+0] = data_in[i][ 7: 0];
@@ -74,10 +94,7 @@
     end
   end
 
-  assign force_data_overwrite = reg2hw.ctrl.force_data_overwrite.q;
-  assign manual_start_trigger = reg2hw.ctrl.manual_start_trigger.q;
-  assign mode                 = mode_e'(reg2hw.ctrl.mode.q);
-  assign start                = reg2hw.trigger.q;
+  assign mode = mode_e'(reg2hw.ctrl.mode.q);
 
   always_comb begin : get_key_len
     unique case (key_len_e'(reg2hw.ctrl.key_len.q))
@@ -90,6 +107,9 @@
     endcase
   end
 
+  assign data_out_re = {reg2hw.data_out3.re, reg2hw.data_out2.re,
+                        reg2hw.data_out1.re, reg2hw.data_out0.re};
+
   // Unused inputs
   // data_out is actually hwo, but we need hrw for hwre
   assign unused_data_out_q[0] = reg2hw.data_out0.q;
@@ -97,77 +117,151 @@
   assign unused_data_out_q[2] = reg2hw.data_out2.q;
   assign unused_data_out_q[3] = reg2hw.data_out3.q;
 
-  // Core modules
-
   // State registers
-  assign state_d = data_in_load ? state_init : state_q;
+  always_comb begin : state_mux
+    unique case (state_sel)
+      STATE_INIT:  state_d = state_init;
+      STATE_ROUND: state_d = add_round_key_out;
+      STATE_CLEAR: state_d = '{default: '0};
+      default      state_d = '{default: 'X};
+    endcase
+  end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin : reg_state
+  always_ff @(posedge clk_i or negedge rst_ni) begin : state_reg
     if (!rst_ni) begin
       state_q <= '{default: '0};
-    end else begin
+    end else if (state_we) begin
       state_q <= state_d;
     end
   end
 
-  // Detect new key, new input, output read
-  // Edge detectors are cleared by the FSM
-  assign key_init_new_d = dec_key_gen ? '0 : key_init_new_q |
-      {reg2hw.key7.qe, reg2hw.key6.qe, reg2hw.key5.qe, reg2hw.key4.qe,
-       reg2hw.key3.qe, reg2hw.key2.qe, reg2hw.key1.qe, reg2hw.key0.qe};
-  assign key_init_new = &key_init_new_d;
+  // Cipher data path
+  aes_sub_bytes aes_sub_bytes (
+    .mode_i ( mode          ),
+    .data_i ( state_q       ),
+    .data_o ( sub_bytes_out )
+  );
 
-  assign data_in_new_d = data_in_load ? '0 : data_in_new_q |
-      {reg2hw.data_in3.qe, reg2hw.data_in2.qe, reg2hw.data_in1.qe, reg2hw.data_in0.qe};
-  assign data_in_new = &data_in_new_d;
+  aes_shift_rows aes_shift_rows (
+    .mode_i ( mode           ),
+    .data_i ( sub_bytes_out  ),
+    .data_o ( shift_rows_out )
+  );
 
-  assign data_out_read_d = data_out_we ? '0 : data_out_read_q |
-      {reg2hw.data_out3.re, reg2hw.data_out2.re, reg2hw.data_out1.re, reg2hw.data_out0.re};
-  assign data_out_read = &data_out_read_d;
+  aes_mix_columns aes_mix_columns (
+    .mode_i ( mode            ),
+    .data_i ( shift_rows_out  ),
+    .data_o ( mix_columns_out )
+  );
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin : reg_edge_detection
-    if (!rst_ni) begin
-      key_init_new_q  <= '0;
-      data_in_new_q   <= '0;
-      data_out_read_q <= '0;
-    end else begin
-      key_init_new_q  <= key_init_new_d;
-      data_in_new_q   <= data_in_new_d;
-      data_out_read_q <= data_out_read_d;
+  always_comb begin : add_round_key_in_mux
+    unique case (add_round_key_in_sel)
+      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 = '{default: 'X};
+    endcase
+  end
+
+  always_comb begin : add_round_key
+    for (int i=0; i<16; i++) begin
+      add_round_key_out[i] = add_round_key_in[i] ^ round_key[i];
     end
   end
 
-  // Control FSM
-  assign dec_key_gen  = 1'b0;
-  assign data_in_load = 1'b0;
-  assign data_out_we  = 1'b0;
+  // Full Key registers
+  always_comb begin : key_full_mux
+    unique case (key_full_sel)
+      KEY_FULL_ENC_INIT: key_full_d = key_init;
+      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 = '{default: '0};
+      default:           key_full_d = '{default: 'X};
+    endcase
+  end
 
-  // placeholders
-  logic     unused_force_data_overwrite;
-  logic     unused_manual_start_trigger;
-  key_len_e unused_key_len;
-  mode_e    unused_mode;
-  logic     unused_start;
-  assign unused_force_data_overwrite = force_data_overwrite;
-  assign unused_manual_start_trigger = manual_start_trigger;
-  assign unused_key_len              = key_len;
-  assign unused_mode                 = mode;
-  assign unused_start                = start;
-  logic unused_data_in_new;
-  logic unused_key_init_new;
-  logic unused_data_out_read;
-  assign unused_data_in_new   = data_in_new;
-  assign unused_key_init_new  = key_init_new;
-  assign unused_data_out_read = data_out_read;
-  logic [31:0] unused_key_init[8];
-  assign unused_key_init[0] = key_init[0];
-  assign unused_key_init[1] = key_init[1];
-  assign unused_key_init[2] = key_init[2];
-  assign unused_key_init[3] = key_init[3];
-  assign unused_key_init[4] = key_init[4];
-  assign unused_key_init[5] = key_init[5];
-  assign unused_key_init[6] = key_init[6];
-  assign unused_key_init[7] = key_init[7];
+  always_ff @(posedge clk_i or negedge rst_ni) begin : key_full_reg
+    if (!rst_ni) begin
+      key_full_q <= '{default: '0};
+    end else if (key_full_we) begin
+      key_full_q <= key_full_d;
+    end
+  end
+
+  // Decryption Key registers
+  always_comb begin : key_dec_mux
+    unique case (key_dec_sel)
+      KEY_DEC_EXPAND: key_dec_d = key_expand_out;
+      KEY_DEC_CLEAR:  key_dec_d = '{default: '0};
+      default:        key_dec_d = '{default: 'X};
+    endcase
+  end
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin : key_dec_reg
+    if (!rst_ni) begin
+      key_dec_q <= '{default: '0};
+    end else if (key_dec_we) begin
+      key_dec_q <= key_dec_d;
+    end
+  end
+
+  // Key expand data path
+  aes_key_expand #(
+  .AES192Enable (AES192Enable)
+  ) aes_key_expand (
+    .clk_i   ( clk_i            ),
+    .rst_ni  ( rst_ni           ),
+    .mode_i  ( mode             ),
+    .clear_i ( key_expand_clear ),
+    .key_i   ( key_full_q       ),
+    .key_o   ( key_expand_out   )
+  );
+
+  always_comb begin : key_words_mux
+    unique case (key_words_sel)
+      KEY_WORDS_0123: begin
+        key_words[0] = key_full_q[0];
+        key_words[1] = key_full_q[1];
+        key_words[2] = key_full_q[2];
+        key_words[3] = key_full_q[3];
+      end
+      KEY_WORDS_2345: begin
+        key_words[0] = key_full_q[2];
+        key_words[1] = key_full_q[3];
+        key_words[2] = key_full_q[4];
+        key_words[3] = key_full_q[5];
+      end
+      KEY_WORDS_4567: begin
+        key_words[0] = key_full_q[4];
+        key_words[1] = key_full_q[5];
+        key_words[2] = key_full_q[6];
+        key_words[3] = key_full_q[7];
+      end
+      KEY_WORDS_ZERO: begin
+        key_words    = '{default: '0};
+      end
+      default: begin
+        key_words    = '{default: 'X};
+      end
+    endcase
+  end
+
+  always_comb begin : conv_key_words_to_bytes
+    for (int i=0; i<4; i++) begin
+      key_bytes[4*i+0] = key_words[i][ 7: 0];
+      key_bytes[4*i+1] = key_words[i][15: 8];
+      key_bytes[4*i+2] = key_words[i][23:16];
+      key_bytes[4*i+3] = key_words[i][31:24];
+    end
+  end
+
+  aes_mix_columns aes_key_mix_columns (
+    .mode_i ( AES_DEC             ),
+    .data_i ( key_bytes           ),
+    .data_o ( key_mix_columns_out )
+  );
+
+  assign round_key = (mode == AES_DEC) ? key_mix_columns_out : key_bytes;
 
   // Output registers
   always_comb begin : conv_state_to_data_out
@@ -176,7 +270,7 @@
     end
   end
 
-  always_ff @(posedge clk_i or negedge rst_ni) begin : reg_data_out
+  always_ff @(posedge clk_i or negedge rst_ni) begin : data_out_reg
     if (!rst_ni) begin
       data_out_q <= '{default: '0};
     end else if (data_out_we) begin
@@ -184,6 +278,47 @@
     end
   end
 
+  // Control
+  aes_control #(
+  .AES192Enable (AES192Enable)
+  ) aes_control (
+    .clk_i                  ( clk_i                              ),
+    .rst_ni                 ( rst_ni                             ),
+
+    .mode_i                 ( mode                               ),
+    .key_len_i              ( key_len                            ),
+    .force_data_overwrite_i ( reg2hw.ctrl.force_data_overwrite.q ),
+    .manual_start_trigger_i ( reg2hw.ctrl.manual_start_trigger.q ),
+    .start_i                ( reg2hw.trigger.q                   ),
+
+    .data_in_qe_i           ( data_in_qe                         ),
+    .key_init_qe_i          ( key_init_qe                        ),
+    .data_out_re_i          ( data_out_re                        ),
+
+    .state_sel_o            ( state_sel                          ),
+    .state_we_o             ( state_we                           ),
+    .add_rk_sel_o           ( add_round_key_in_sel               ),
+    .key_full_sel_o         ( key_full_sel                       ),
+    .key_full_we_o          ( key_full_we                        ),
+    .key_dec_sel_o          ( key_dec_sel                        ),
+    .key_dec_we_o           ( key_dec_we                         ),
+    .key_expand_clear_o     ( key_expand_clear                   ),
+    .key_words_sel_o        ( key_words_sel                      ),
+
+    .data_out_we_o          ( data_out_we                        ),
+
+    .trigger_o              ( hw2reg.trigger.d                   ),
+    .trigger_we_o           ( hw2reg.trigger.de                  ),
+    .output_valid_o         ( hw2reg.status.output_valid.d       ),
+    .output_valid_we_o      ( hw2reg.status.output_valid.de      ),
+    .input_ready_o          ( hw2reg.status.input_ready.d        ),
+    .input_ready_we_o       ( hw2reg.status.input_ready.de       ),
+    .idle_o                 ( hw2reg.status.idle.d               ),
+    .idle_we_o              ( hw2reg.status.idle.de              ),
+    .stall_o                ( hw2reg.status.stall.d              ),
+    .stall_we_o             ( hw2reg.status.stall.de             )
+  );
+
   // Outputs
   assign hw2reg.data_out0.d = data_out_q[0];
   assign hw2reg.data_out1.d = data_out_q[1];
@@ -193,20 +328,4 @@
   assign hw2reg.ctrl.key_len.d  = {key_len};
   assign hw2reg.ctrl.key_len.de = reg2hw.ctrl.key_len.qe;
 
-  assign hw2reg.trigger.d   = 1'b0;
-  assign hw2reg.trigger.de  = 1'b1;
-
-  assign hw2reg.status.idle.d   = 1'b0;
-  assign hw2reg.status.idle.de  = 1'b1;
-  assign hw2reg.status.stall.d  = 1'b0;
-  assign hw2reg.status.stall.de = 1'b1;
-
-  // clear once all output regs have been read
-  assign hw2reg.status.output_valid.d  = data_out_we;
-  assign hw2reg.status.output_valid.de = data_out_we | data_out_read;
-
-  // clear once all input regs have been written
-  assign hw2reg.status.input_ready.d   = ~data_in_new;
-  assign hw2reg.status.input_ready.de  =  data_in_new | data_in_load;
-
 endmodule
diff --git a/hw/ip/aes/rtl/aes_key_expand.sv b/hw/ip/aes/rtl/aes_key_expand.sv
new file mode 100644
index 0000000..d7961ea
--- /dev/null
+++ b/hw/ip/aes/rtl/aes_key_expand.sv
@@ -0,0 +1,31 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// AES KeyExpand
+
+module aes_key_expand #(
+  parameter bit AES192Enable = 1
+) (
+  input  logic           clk_i,
+  input  logic           rst_ni,
+  input  aes_pkg::mode_e mode_i,
+  input  logic           clear_i,
+  input  logic [31:0]    key_i [8],
+  output logic [31:0]    key_o [8]
+);
+
+import aes_pkg::*;
+
+// dummy only
+logic  unused_clk;
+logic  unused_rst_n;
+mode_e unused_mode;
+logic  unused_clear;
+assign unused_clk   = clk_i;
+assign unused_rst_n = rst_ni;
+assign unused_mode  = mode_i;
+assign unused_clear = clear_i;
+assign key_o        = key_i;
+
+endmodule
diff --git a/hw/ip/aes/rtl/aes_mix_columns.sv b/hw/ip/aes/rtl/aes_mix_columns.sv
new file mode 100644
index 0000000..715ced0
--- /dev/null
+++ b/hw/ip/aes/rtl/aes_mix_columns.sv
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// AES MixColumns
+
+module aes_mix_columns (
+  input  aes_pkg::mode_e mode_i,
+  input  logic [7:0]     data_i [16],
+  output logic [7:0]     data_o [16]
+);
+
+import aes_pkg::*;
+
+// dummy only
+mode_e unused_mode;
+assign unused_mode = mode_i;
+assign data_o      = data_i;
+
+endmodule
diff --git a/hw/ip/aes/rtl/aes_pkg.sv b/hw/ip/aes/rtl/aes_pkg.sv
index 5d8fa61..be8e065 100644
--- a/hw/ip/aes/rtl/aes_pkg.sv
+++ b/hw/ip/aes/rtl/aes_pkg.sv
@@ -17,4 +17,35 @@
   AES_256 = 3'b100
 } key_len_e;
 
+typedef enum logic [1:0] {
+  STATE_INIT,
+  STATE_ROUND,
+  STATE_CLEAR
+} state_sel_e;
+
+typedef enum logic [1:0] {
+  ADD_RK_INIT,
+  ADD_RK_ROUND,
+  ADD_RK_FINAL
+} add_rk_sel_e;
+
+typedef enum logic [1:0] {
+  KEY_FULL_ENC_INIT,
+  KEY_FULL_DEC_INIT,
+  KEY_FULL_ROUND,
+  KEY_FULL_CLEAR
+} key_full_sel_e;
+
+typedef enum logic {
+  KEY_DEC_EXPAND,
+  KEY_DEC_CLEAR
+} key_dec_sel_e;
+
+typedef enum logic [1:0] {
+  KEY_WORDS_0123,
+  KEY_WORDS_2345,
+  KEY_WORDS_4567,
+  KEY_WORDS_ZERO
+} key_words_sel_e;
+
 endpackage
diff --git a/hw/ip/aes/rtl/aes_shift_rows.sv b/hw/ip/aes/rtl/aes_shift_rows.sv
new file mode 100644
index 0000000..c72751c
--- /dev/null
+++ b/hw/ip/aes/rtl/aes_shift_rows.sv
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// AES ShiftRows
+
+module aes_shift_rows (
+  input  aes_pkg::mode_e mode_i,
+  input  logic [7:0]     data_i [16],
+  output logic [7:0]     data_o [16]
+);
+
+import aes_pkg::*;
+
+// dummy only
+mode_e unused_mode;
+assign unused_mode = mode_i;
+assign data_o      = data_i;
+
+endmodule
diff --git a/hw/ip/aes/rtl/aes_sub_bytes.sv b/hw/ip/aes/rtl/aes_sub_bytes.sv
new file mode 100644
index 0000000..b64d3e2
--- /dev/null
+++ b/hw/ip/aes/rtl/aes_sub_bytes.sv
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// AES SubBytes
+
+module aes_sub_bytes (
+  input  aes_pkg::mode_e mode_i,
+  input  logic [7:0]     data_i [16],
+  output logic [7:0]     data_o [16]
+);
+
+import aes_pkg::*;
+
+// dummy only
+mode_e unused_mode;
+assign unused_mode = mode_i;
+assign data_o      = data_i;
+
+endmodule