Skip to content
Snippets Groups Projects
soclabs_ahb_aes128_ctrl.v 25.44 KiB
 //-----------------------------------------------------------------------------
// top-level soclabs example AHB interface
// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
//
// Contributors
//
// David Flynn (d.w.flynn@soton.ac.uk)
//
// Copyright (C) 2023, SoC Labs (www.soclabs.org)
//-----------------------------------------------------------------------------

module soclabs_ahb_aes128_ctrl(
// -------------------------------------------------------
// MCU interface
// -------------------------------------------------------
  input  wire        ahb_hclk,      // Clock
  input  wire        ahb_hresetn,   // Reset
  input  wire        ahb_hsel,      // Device select
  input  wire [15:0] ahb_haddr16,   // Address for byte select
  input  wire  [1:0] ahb_htrans,    // Transfer control
  input  wire  [2:0] ahb_hsize,     // Transfer size
  input  wire  [3:0] ahb_hprot,     // Protection control
  input  wire        ahb_hwrite,    // Write control
  input  wire        ahb_hready,    // Transfer phase done
  input  wire [31:0] ahb_hwdata,    // Write data
  output wire        ahb_hreadyout, // Device ready
  output wire [31:0] ahb_hrdata,    // Read data output
  output wire        ahb_hresp,     // Device response
// stream data
  output wire        drq_ipdma128,  // (to) DMAC input burst request
  input  wire        dlast_ipdma128,// (from) DMAC input burst end (last transfer)
  output wire        drq_opdma128,  // (to) DMAC output dma burst request
  input  wire        dlast_opdma128,// (from) DMAC output burst end (last transfer)
  output wire        irq_key128,
  output wire        irq_ip128,
  output wire        irq_op128,
  output wire        irq_error,
  output wire        irq_merged     // combined interrrupt request (to CPU)
  );

  //----------------------------------------------------------------
  // Internal parameter definitions.
  //----------------------------------------------------------------

///typedef struct {
///     __I  uint32_t CORE_NAME[2];   /* 0x0000-0007 */
///     __I  uint32_t CORE_VERSION;   /* 0x0008-000B */
///          uint32_t RESRV0C;        /* 0x000C */
///     __IO uint32_t CTRL;           /* 0x0010 */
///     __O  uint32_t CTRL_SET;       /* 0x0014 */
///     __O  uint32_t CTRLL_CLR;      /* 0x0018 */
///     __I  uint32_t STATUS;         /* 0x001c */
///     __IO uint32_t QUAL;           /* 0x0020 */
///          uint32_t RESRV24[3];     /* 0x0024 - 2F*/
///     __IO uint32_t DRQ_MSK;        /* 0x0030 */
///     __O  uint32_t DRQ_MSK_SET;    /* 0x0034 */
///     __O  uint32_t DRQ_MSK_CLR;    /* 0x0038 */
///     __I  uint32_t DRQ_STATUS;     /* 0x003C */
///     __IO uint32_t IRQ_MSK;        /* 0x0040 */
///     __O  uint32_t IRQ_MSK_SET;    /* 0x0044 */
///     __O  uint32_t IRQ_MSK_CLR;    /* 0x0048 */
///     __I  uint32_t IRQ_STATUS;     /* 0x004C */
///          uint32_t RESRV50[4076];  /* 0x0050-0x3FFC (4096-20 words) */
///     __IO uint8_t KEY128[0x4000];   /* 0x4000-7FFF (0x3FFF is last alias) */
///     __IO uint8_t TXTIP128[0x4000]; /* 0x8000-BFFF (0x3FFF is last alias) */
///     __I  uint8_t TXTOP128[0x4000]; /* 0xC000-FFFF (0x3FFF is last alias) */
///} AES128_TypeDef;


// CORE ID
  localparam ADDR_CORE_NAME0  = 16'h0000;
  localparam ADDR_CORE_NAME1  = 16'h0004;
  localparam ADDR_CORE_VERSION= 16'h0008;
  localparam CORE_NAME0       = 32'h61657331; // "aes1"
  localparam CORE_NAME1       = 32'h32382020; // "28  "
  localparam CORE_VERSION     = 32'h302e3031; // "0.01"

// CTRL control register with bit-set/bit-clear options
  localparam ADDR_CTRL        = 16'h0010;
  localparam ADDR_CTRL_SET    = 16'h0014;
  localparam ADDR_CTRL_CLR    = 16'h0018;
  localparam CTRL_REG_WIDTH   = 8;
  localparam CTRL_BIT_MAX     = (CTRL_REG_WIDTH-1);
  localparam CTRL_KEY_REQ_BIT = 0;
  localparam CTRL_IP_REQ_BIT  = 1;
  localparam CTRL_OP_REQ_BIT  = 2;
  localparam CTRL_ERR_REQ_BIT = 3;
  localparam CTRL_KEYOK_BIT   = 4;
  localparam CTRL_VALID_BIT   = 5;
  localparam CTRL_BYPASS_BIT  = 6;
  localparam CTRL_ENCODE_BIT  = 7;
// STAT status regisyer 
  localparam ADDR_STAT        = 16'h001c;
  localparam STAT_REG_WIDTH   = 8;
  localparam STAT_BIT_MAX     = (STAT_REG_WIDTH-1);
  localparam STAT_KEYREQ_BIT  = 0;
  localparam STAT_INPREQ_BIT  = 1;
  localparam STAT_OUTREQ_BIT  = 2;
  localparam STAT_ERROR_BIT   = 3;
  localparam STAT_KEYOK_BIT   = 4;
  localparam STAT_VALID_BIT   = 5;

// QUAL qualifier field
  localparam ADDR_QUAL        = 16'h0020;
  localparam QUAL_REG_WIDTH   = 32;
  localparam QUAL_BIT_MAX     = (QUAL_REG_WIDTH-1);

// DREQ DMAC request control with bit-set/bit-clear options
  localparam ADDR_DREQ        = 16'h0030;
  localparam ADDR_DREQ_SET    = 16'h0034;
  localparam ADDR_DREQ_CLR    = 16'h0038;
  localparam ADDR_DREQ_ACT    = 16'h003c;
  localparam DREQ_REG_WIDTH   = 3;
  localparam DREQ_BIT_MAX     = (DREQ_REG_WIDTH-1);
  localparam  REQ_KEYBUF_BIT  = 0;
  localparam  REQ_IP_BUF_BIT  = 1;
  localparam  REQ_OP_BUF_BIT  = 2;

// IREQ CPU interrupt request control with bit-set/bit-clear options
  localparam ADDR_IREQ        = 16'h0040;
  localparam ADDR_IREQ_SET    = 16'h0044;
  localparam ADDR_IREQ_CLR    = 16'h0048;
  localparam ADDR_IREQ_ACT    = 16'h004c;
  localparam IREQ_REG_WIDTH   = 4;
  localparam IREQ_BIT_MAX     = (IREQ_REG_WIDTH-1);
  localparam  REQ_ERROR_BIT   = 3;

  localparam ADDR_KEY_BASE    = 16'h4000;
  localparam ADDR_KEY0        = 16'h4000;
  localparam ADDR_KEY3        = 16'h400c;
  localparam ADDR_KEY7        = 16'h401c;

  localparam ADDR_IBUF_BASE   = 16'h8000;
  localparam ADDR_IBUF_0      = 16'h8000;
  localparam ADDR_IBUF_3      = 16'h800c;

  localparam ADDR_OBUF_BASE   = 16'hc000;
  localparam ADDR_OBUF_3      = 16'hc00c;

 
 // --------------------------------------------------------------------------
  // Internal regs/wires
  // --------------------------------------------------------------------------

  reg   [15:0] addr16_r;
  reg          sel_r;
  reg          wcyc_r;
  reg          rcyc_r;
  reg    [3:0] byte4_r;

  wire         key128_load_ack;
  wire         ip128_load_ack;
  wire         op128_load_ack;

  // --------------------------------------------------------------------------
  // AHB slave byte buffer interface, support for unaligned data transfers
  // --------------------------------------------------------------------------

  wire   [1:0] byt_adr = ahb_haddr16[1:0];
  // generate next byte enable decodes for Word/Half/Byte CPU/DMA accesses
  wire   [3:0] byte_nxt;
  assign byte_nxt[0] = (ahb_hsize[1])|((ahb_hsize[0])&(!byt_adr[1]))|(byt_adr[1:0]==2'b00);
  assign byte_nxt[1] = (ahb_hsize[1])|((ahb_hsize[0])&(!byt_adr[1]))|(byt_adr[1:0]==2'b01);
  assign byte_nxt[2] = (ahb_hsize[1])|((ahb_hsize[0])&( byt_adr[1]))|(byt_adr[1:0]==2'b10);
  assign byte_nxt[3] = (ahb_hsize[1])|((ahb_hsize[0])&( byt_adr[1]))|(byt_adr[1:0]==2'b11);

  // de-pipelined registered access signals
  always @(posedge ahb_hclk or negedge ahb_hresetn)
    if (!ahb_hresetn)
    begin
      addr16_r <= 16'h0000;
      sel_r    <= 1'b0;
      wcyc_r   <= 1'b0;
      rcyc_r   <= 1'b0;
      byte4_r  <= 4'b0000;
    end else if (ahb_hready)
    begin
      addr16_r <= (ahb_hsel & ahb_htrans[1]) ?  ahb_haddr16 : addr16_r;
      sel_r    <= (ahb_hsel & ahb_htrans[1]);
      wcyc_r   <= (ahb_hsel & ahb_htrans[1]  &  ahb_hwrite);
      rcyc_r   <= (ahb_hsel & ahb_htrans[1]  & !ahb_hwrite);
      byte4_r  <= (ahb_hsel & ahb_htrans[1]) ?  byte_nxt[3:0] : 4'b0000;
    end 


// pipelined "early" last access decodes, for PL230 dma_ack timing to deassert dma requests
//  wire ahb128_last  = ahb_hsel &  ahb_htrans[1] & ahb_hready & ahb_haddr16[3] & ahb_haddr16[2] & byte_nxt[3];
//  wire ahb128_wlast = ahb_last &  ahb_hwrite & |ahb_haddr[15:14]; // address phase of last write transfer
//  wire ahb128_rlast = ahb_last & !ahb_hwrite & |ahb_haddr[15:14]; // address phase of last read transfer
  
  wire wlast128     = |ahb_haddr16[15:14] & addr16_r[3] & addr16_r[2] & byte4_r[3] & wcyc_r; // write last pulse
  wire rlast128     = &ahb_haddr16[15:14] & addr16_r[3] & addr16_r[2] & byte4_r[3] & rcyc_r; // read last pulse

  //----------------------------------------------------------------
  // API register state and wiring
  //
  //----------------------------------------------------------------

  reg   [CTRL_BIT_MAX:0] control;
  reg   [QUAL_BIT_MAX:0] param;
  reg   [DREQ_BIT_MAX:0] drq_enable;
  reg   [IREQ_BIT_MAX:0] irq_enable;

  wire  [STAT_BIT_MAX:0] status;
  wire  [DREQ_BIT_MAX:0] drq_active;
  wire  [IREQ_BIT_MAX:0] irq_active;

  wire [31:0] rd_keybuf;
  wire [31:0] rd_ipbuf;
  wire [31:0] rd_opbuf;
 
  //----------------------------------------------------------------
  // API write decoder
  //
  //----------------------------------------------------------------

  wire sel_mode   = sel_r & (addr16_r[15: 8] == 0);
  wire sel_keybuf = sel_r & (addr16_r[15:14] == 1);
  wire sel_ipbuf  = sel_r & (addr16_r[15:14] == 2);
  wire sel_opbuf  = sel_r & (addr16_r[15:14] == 3);
// add address map "last" transfer signalling when last (byte) of alias map is written 
  wire alast_key128 = sel_keybuf & wcyc_r & (&addr16_r[13:2]) & byte4_r[3];
  wire alast_ip128  = sel_ipbuf  & wcyc_r & (&addr16_r[13:2]) & byte4_r[3];
  wire alast_op128  = sel_opbuf  & rcyc_r & (&addr16_r[13:2]) & byte4_r[3];

  always @(posedge ahb_hclk or negedge ahb_hresetn)
   if (!ahb_hresetn) begin
     control    <= {CTRL_REG_WIDTH{1'b0}};
     param      <= {QUAL_REG_WIDTH{1'b0}};
     drq_enable <= {DREQ_REG_WIDTH{1'b0}};
     irq_enable <= {IREQ_REG_WIDTH{1'b0}};
     end
   else if (sel_mode & wcyc_r & byte4_r[0])
     case ({addr16_r[15:2],2'b00})
       ADDR_CTRL    : control    <=  ahb_hwdata[CTRL_BIT_MAX:0];              // overwrite ctl reg
       ADDR_CTRL_SET: control    <=  ahb_hwdata[CTRL_BIT_MAX:0] | control;    // bit set ctl mask pattern
       ADDR_CTRL_CLR: control    <= ~ahb_hwdata[CTRL_BIT_MAX:0] & control;    // bit clear ctl mask pattern
       ADDR_QUAL    : param      <=  ahb_hwdata[QUAL_BIT_MAX:0];              // write qual pattern
       ADDR_DREQ    : drq_enable <=  ahb_hwdata[DREQ_BIT_MAX:0];              // overwrite dreq reg
       ADDR_DREQ_SET: drq_enable <=  ahb_hwdata[DREQ_BIT_MAX:0] | drq_enable; // bit set dreq mask pattern
       ADDR_DREQ_CLR: drq_enable <= ~ahb_hwdata[DREQ_BIT_MAX:0] & drq_enable; // bit clear dreq mask pattern
       ADDR_IREQ    : irq_enable <=  ahb_hwdata[IREQ_BIT_MAX:0];              // overwrite ireq reg
       ADDR_IREQ_SET: irq_enable <=  ahb_hwdata[IREQ_BIT_MAX:0] | irq_enable; // bit set ireq mask pattern
       ADDR_IREQ_CLR: irq_enable <= ~ahb_hwdata[IREQ_BIT_MAX:0] & irq_enable; // bit clear ireq mask pattern
       default: ;
     endcase
   else if (sel_keybuf & wcyc_r & (dlast_ipdma128 | alast_key128)) // key terminate
     drq_enable[0] <= 1'b0;
   else if (sel_ipbuf  & wcyc_r & (dlast_ipdma128 | alast_ip128)) // ip-buffer terminate
     drq_enable[1] <= 1'b0;
   else if (sel_opbuf & rcyc_r  & (dlast_opdma128 | alast_op128)) // op-buffer complete
     drq_enable[2] <= 1'b0;

  //----------------------------------------------------------------
  // API read decoder
  //
  //----------------------------------------------------------------

reg [31:0] rdata32; // mux read data

  always @*
    begin : read_decoder
      rdata32  = 32'hbad0bad;
      if (sel_r & rcyc_r)
        case ({addr16_r[15:2],2'b00})
          ADDR_CORE_NAME0   : rdata32 = CORE_NAME0; 
          ADDR_CORE_NAME1   : rdata32 = CORE_NAME1; 
          ADDR_CORE_VERSION : rdata32 = CORE_VERSION;
          ADDR_CTRL     : rdata32 = {{(32-CTRL_REG_WIDTH){1'b0}}, control};
          ADDR_STAT     : rdata32 = {{(32-STAT_REG_WIDTH){1'b0}}, status};
          ADDR_QUAL     : rdata32 = {{(32-QUAL_REG_WIDTH){1'b0}}, param};
          ADDR_DREQ     : rdata32 = {{(32-DREQ_REG_WIDTH){1'b0}}, drq_enable};
          ADDR_DREQ_ACT : rdata32 = {{(32-DREQ_REG_WIDTH){1'b0}}, drq_active};
          ADDR_IREQ     : rdata32 = {{(32-IREQ_REG_WIDTH){1'b0}}, irq_enable};
          ADDR_IREQ_ACT : rdata32 = {{(32-DREQ_REG_WIDTH){1'b0}}, irq_active};
        default:
          if      (sel_keybuf) rdata32 = rd_keybuf;
          else if (sel_ipbuf)  rdata32 = rd_ipbuf;
          else if (sel_opbuf)  rdata32 = rd_opbuf;
        endcase
    end // read_decoder

  assign ahb_hrdata = rdata32;

  assign ahb_hreadyout = 1'b1; // zero wait state interface
  assign ahb_hresp     = 1'b0;
    
  // --------------------------------------------------------------------------
  // Key Input Buffer - keybuf
  // --------------------------------------------------------------------------

  wire [127:0] key128_be;

  soclabs_iobuf_reg128
  #(.WRITE_ONLY     (1),
    .WRITE_ZPAD     (0))
  u_reg128_key
  (
    .clk         (ahb_hclk        ), // Clock
    .rst_b       (ahb_hresetn     ), // Reset
    .sel_r       (sel_keybuf      ), // Bank decode select
    .wcyc_r      (wcyc_r          ), // Write cycle (wdata32 valid)
    .rcyc_r      (rcyc_r          ), // Read cycle (return rdata32)
    .word2_r     (addr16_r[3:2]   ), // Address for word select
    .byte4_r     (byte4_r[3:0]    ), // Byte select decoded (up to 4 enabled)
    .wdata32     (ahb_hwdata[31:0]), // Write data (byte lane qualified)
    .rdata32     (rd_keybuf       ), // Read data output
    .dma128_ack  (key128_load_ack ), // DMA burst acknowledge
    .out128_le   (                ), // Big-Endian 128-bit value
    .out128_be   (key128_be       )  // Big-Endian 128-bit value
  );

  // --------------------------------------------------------------------------
  // Data Input Buffer - ipbuf
  // --------------------------------------------------------------------------

  wire [127:0] ip128_le;
  wire [127:0] ip128_be;

  soclabs_iobuf_reg128
  #(.WRITE_ONLY     (0),
    .WRITE_ZPAD     (1))
  u_reg128_ip
  (
    .clk         (ahb_hclk        ), // Clock
    .rst_b       (ahb_hresetn     ), // Reset
    .sel_r       (sel_ipbuf       ), // Bank decode select
    .wcyc_r      (wcyc_r          ), // Write cycle (wdata32 valid)
    .rcyc_r      (rcyc_r          ), // Read cycle (return rdata32)
    .word2_r     (addr16_r[3:2]   ), // Address for word select
    .byte4_r     (byte4_r[3:0]    ), // Byte select decoded (up to 4 enabled)
    .wdata32     (ahb_hwdata[31:0]), // Write data (byte lane qualified)
    .rdata32     (rd_ipbuf        ), // Read data output
    .dma128_ack  (ip128_load_ack  ), // DMA burst acknowledge
    .out128_le   (ip128_le        ), // Big-Endian 128-bit value
    .out128_be   (ip128_be        )  // Big-Endian 128-bit value
  );

  // --------------------------------------------------------------------------
  // Data Output Buffer - opbufsel_keybuf
  // --------------------------------------------------------------------------

  wire [127:0] op128_be;
  wire [127:0] op128_muxed = (control[CTRL_BYPASS_BIT]) ? ip128_be : op128_be;
  
  wire [31:0] op_slice32 [0:3];
  assign op_slice32[3] = {op128_muxed[  7:  0],op128_muxed[ 15:  8],op128_muxed[ 23: 16],op128_muxed[ 31: 24]};
  assign op_slice32[2] = {op128_muxed[ 39: 32],op128_muxed[ 47: 40],op128_muxed[ 55: 48],op128_muxed[ 63: 56]};
  assign op_slice32[1] = {op128_muxed[ 71: 64],op128_muxed[ 79: 72],op128_muxed[ 87: 80],op128_muxed[ 95: 88]};
  assign op_slice32[0] = {op128_muxed[103: 96],op128_muxed[111:104],op128_muxed[119:112],op128_muxed[127:120]};

  // 32-bit addressed read data
  assign rd_opbuf = op_slice32[addr16_r[3:2]];

  assign op128_load_ack = (sel_opbuf & rcyc_r & addr16_r[3] & addr16_r[2] & byte4_r[3]);

  // --------------------------------------------------------------------------
  // example aes128 engine timing
  // --------------------------------------------------------------------------
  // --------------------------------------------------------------------------
  // AES-specific control interface
  // --------------------------------------------------------------------------

wire aes128_encode = control[CTRL_ENCODE_BIT];
wire aes256_keysize = 1'b0;

wire aes_keyloaded_pulse = key128_load_ack; // pulse on last byte load of key128
wire aes_dataloaded_pulse= ip128_load_ack;  // pulse on last byte load of text128
wire aes_ready;
wire aes_valid;

// state machine control
reg  aes_ready_del;
reg  aes_init;
reg  aes_next;
reg  aes_key_busy;
reg  aes_key_rdy;
reg  aes_res_busy;
reg  aes_res_rdy;
reg  aes_err;

  always @(posedge ahb_hclk or negedge ahb_hresetn)
    if (!ahb_hresetn) begin
      aes_ready_del <= 1'b0;
      aes_init      <= 1'b0;
      aes_next      <= 1'b0;
      aes_key_busy  <= 1'b0;
      aes_key_rdy   <= 1'b0;
      aes_res_busy  <= 1'b0;
      aes_res_rdy   <= 1'b0;
      aes_err       <= 1'b0;
    end else begin
      aes_ready_del <= aes_ready; // delay for rising edge detect
      aes_init      <= aes_keyloaded_pulse;
      aes_next      <= aes_dataloaded_pulse;
      aes_key_busy  <= (aes_init) | (aes_key_busy & !(aes_ready & !aes_ready_del)); // hold until key expansion done
      aes_key_rdy   <= (aes_key_busy & aes_ready & !aes_ready_del) // expanded key ready
                     | (aes_key_rdy & !(sel_keybuf & wcyc_r));     // hold until any key update
      aes_res_busy  <= (aes_next) | (aes_res_busy & !(aes_ready & !aes_ready_del)); // hold until block processing done
      aes_res_rdy   <= (aes_res_busy & aes_ready & !aes_ready_del) // block ready
                     | (aes_res_rdy & !op128_load_ack);           // hold until output transferred
      aes_err       <= (!aes_key_rdy & ((sel_ipbuf & wcyc_r) | (sel_opbuf & rcyc_r)))
                     | (aes_err & !(sel_keybuf & wcyc_r));
    end

  assign drq_active[REQ_KEYBUF_BIT] = control[CTRL_KEY_REQ_BIT] & (!aes_keyloaded_pulse & !aes_init & !aes_key_busy & !aes_key_rdy);
  assign drq_active[REQ_IP_BUF_BIT] = control[CTRL_IP_REQ_BIT] & (!aes_dataloaded_pulse & !aes_next & !aes_res_busy & !aes_res_rdy & aes_key_rdy);
  assign drq_active[REQ_OP_BUF_BIT] = control[CTRL_OP_REQ_BIT] & (!aes_res_busy &  aes_res_rdy);

// input DMA channel shared by Key and Data-In
  assign drq_ipdma128 = (drq_enable[REQ_KEYBUF_BIT] & drq_active[REQ_KEYBUF_BIT] & !wlast128) // if key DMA enabled
                      | (drq_enable[REQ_IP_BUF_BIT] & drq_active[REQ_IP_BUF_BIT] & !wlast128) // if ip128 DMA requested
                      ;
                      
// output DMA channel for Data-Out
  assign drq_opdma128 = (drq_enable[REQ_OP_BUF_BIT]  & drq_active[REQ_OP_BUF_BIT] & !rlast128); // if op128 DMA requested

// and Interrupt requests are masked out if corresponding DMA requests are enabled
  assign irq_active[REQ_KEYBUF_BIT] = drq_active[REQ_KEYBUF_BIT] & !drq_enable[REQ_KEYBUF_BIT];
  assign irq_active[REQ_IP_BUF_BIT] = drq_active[REQ_IP_BUF_BIT] & !drq_enable[REQ_IP_BUF_BIT];
  assign irq_active[REQ_OP_BUF_BIT] = drq_active[REQ_OP_BUF_BIT] & !drq_enable[REQ_OP_BUF_BIT];
  assign irq_active[REQ_ERROR_BIT ] = control[CTRL_ERR_REQ_BIT]   & aes_err; // error raised in SW

  assign irq_key128 = irq_active[REQ_KEYBUF_BIT] & irq_enable[REQ_KEYBUF_BIT];
  assign irq_ip128  = irq_active[REQ_IP_BUF_BIT] & irq_enable[REQ_IP_BUF_BIT];
  assign irq_op128  = irq_active[REQ_OP_BUF_BIT] & irq_enable[REQ_OP_BUF_BIT];
  assign irq_error  = irq_active[REQ_ERROR_BIT ] & irq_enable[REQ_ERROR_BIT ];
// merge and mask if not DRQ
  assign irq_merged = irq_key128 | irq_ip128 | irq_op128 | irq_error;
  

// wire up status port  
  assign status[2:0]            = control [2:0];
  assign status[STAT_ERROR_BIT] = (!aes_res_busy & !aes_key_rdy);
  assign status[STAT_KEYOK_BIT] = aes_key_rdy;
  assign status[STAT_VALID_BIT] = aes_res_rdy;
  assign status[7:6]            = control [7:6];

  //----------------------------------------------------------------
  // core instantiation.
  //----------------------------------------------------------------
  aes_core core(
                .clk(ahb_hclk),
                .reset_n(ahb_hresetn),

                .encdec(aes128_encode),
                .init(aes_init),
                .next(aes_next),
                .ready(aes_ready),

                .key({key128_be,key128_be}),
                .keylen(aes256_keysize),

                .block(ip128_be),
                .result(op128_be),
                .result_valid(aes_valid)
               );
                             
endmodule

module soclabs_iobuf_reg128
 #(
  parameter  WRITE_ONLY = 0,
  parameter  WRITE_ZPAD = 0
  ) (
// -------------------------------------------------------
// de-pipelined register interface
// -------------------------------------------------------
// ahb
  input  wire         clk,        // Clock
  input  wire         rst_b,      // Reset
  input  wire         sel_r,      // Bank decode select
  input  wire         wcyc_r,     // Write cycle (wdata32 valid)
  input  wire         rcyc_r,     // Read cycle (return rdata32)
  input  wire   [1:0] word2_r,    // Address for word select
  input  wire   [3:0] byte4_r,    // Byte select decoded (up to 4 enabled)
  input  wire  [31:0] wdata32,    // Write data (byte lae qualified)
  output wire  [31:0] rdata32,    // Read data output
  output wire         dma128_ack, // DMA burst acknowledge
  output wire [127:0] out128_le,  // Litte-Endian 128-bit value
  output wire [127:0] out128_be   // Big-Endian 128-bit value
) ;

  reg   [7:0] byte0 [0:3];
  reg   [7:0] byte1 [0:3];
  reg   [7:0] byte2 [0:3];
  reg   [7:0] byte3 [0:3];
  reg         ack128;

  wire zpad_cfg = (WRITE_ZPAD==0) ? 1'b0 : 1'b1;

// byte-0 array; flush on write to word-0, byte-0
// else addressed word byte-0 write
  always @(posedge clk or negedge rst_b)
    if (!rst_b)
      begin byte0[0] <= 8'h00; byte0[1] <= 8'h00; byte0[2] <= 8'h00; byte0[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r & byte4_r[0] & !word2_r[1] & !word2_r[0]) // Z-PAD rest
      begin byte0[0] <= wdata32[ 7: 0]; byte0[1] <= 8'h00; byte0[2] <= 8'h00; byte0[3] <= 8'h00; end
    else if (sel_r & wcyc_r & byte4_r[0])
      byte0[word2_r[1:0]] <= wdata32[ 7: 0];
   
// byte-1 array; flush on write to word-0, byte-0 if byte-1 not also written
// flush rest on write to word-0, byte-0 and byte-1 also written
// else address word byte-1 write
  always @(posedge clk or negedge rst_b)
    if (!rst_b)
      begin byte1[0] <= 8'h00; byte1[1] <= 8'h00; byte1[2] <= 8'h00; byte1[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r & !byte4_r[1] & !word2_r[1] & !word2_r[0] & byte4_r[0]) // Z-PAD
      begin byte1[0] <= 8'h00; byte1[1] <= 8'h00; byte1[2] <= 8'h00; byte1[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r &  byte4_r[1] & !word2_r[1] & !word2_r[0] & byte4_r[0]) // Z-PAD rest
      begin byte1[0] <= wdata32[15: 8]; byte1[1] <= 8'h00; byte1[2] <= 8'h00; byte1[3] <= 8'h00; end
    else if (sel_r & wcyc_r & byte4_r[1])
      byte1[word2_r[1:0]] <= wdata32[15: 8];
   
// byte-2 array; flush on write to word-0, byte-0 if byte-2 not also written
// flush rest on write to word-0, byte-0 and byte-2 also written
// else address word byte-2 write
  always @(posedge clk or negedge rst_b)
    if (!rst_b)
      begin byte2[0] <= 8'h00; byte2[1] <= 8'h00; byte2[2] <= 8'h00; byte2[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r & !byte4_r[2] & !word2_r[1] & !word2_r[0] & byte4_r[0]) // Z-PAD
      begin byte2[0] <= 8'h00; byte2[1] <= 8'h00; byte2[2] <= 8'h00; byte2[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r &  byte4_r[2] & !word2_r[1] & !word2_r[0] & byte4_r[0]) // Z-PAD rest
      begin byte2[0] <= wdata32[23:16]; byte2[1] <= 8'h00; byte2[2] <= 8'h00; byte2[3] <= 8'h00; end
    else if (sel_r & wcyc_r & byte4_r[2])
      byte2[word2_r[1:0]] <= wdata32[23:16];
   
// byte-3 array; flush on write to word-0, byte-0 if byte-3 not also written
// flush rest on write to word-0, byte-0 and byte-3 also written
// else address word byte-3 write
  always @(posedge clk or negedge rst_b)
    if (!rst_b)
      begin byte3[0] <= 8'h00; byte3[1] <= 8'h00; byte3[2] <= 8'h00; byte3[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r & !byte4_r[3] & !word2_r[1] & !word2_r[0] & byte4_r[0]) // Z-PAD
      begin byte3[0] <= 8'h00; byte3[1] <= 8'h00; byte3[2] <= 8'h00; byte3[3] <= 8'h00; end
    else if (zpad_cfg & sel_r & wcyc_r &  byte4_r[3] & !word2_r[1] & !word2_r[0] & byte4_r[0]) // Z-PAD rest
      begin byte3[0] <= wdata32[31:24]; byte3[1] <= 8'h00; byte3[2] <= 8'h00; byte3[3] <= 8'h00; end
    else if (sel_r & wcyc_r & byte4_r[3])
      byte3[word2_r[1:0]] <= wdata32[31:24];

  // ack on write to final byte [15]   
  always @(posedge clk or negedge rst_b)
    if (!rst_b)
      ack128 <= 1'b0;
    else
      ack128 <= sel_r & wcyc_r & word2_r[1] & word2_r[0] & byte4_r[3];

  assign dma128_ack = ack128;

// byte reverse per word for Big Endian AES engine
  assign out128_be = {byte0[0], byte1[0], byte2[0], byte3[0],
                      byte0[1], byte1[1], byte2[1], byte3[1],
                      byte0[2], byte1[2], byte2[2], byte3[2],
                      byte0[3], byte1[3], byte2[3], byte3[3]};
                   
// byte reverse per word for Big Endian AES engine
  assign out128_le = {byte3[3], byte2[3], byte1[3], byte0[3],
                      byte3[2], byte2[2], byte1[2], byte0[2],
                      byte3[1], byte2[1], byte1[1], byte0[1],
                      byte3[0], byte2[0], byte1[0], byte0[0]};
                   
// little-endian read data (if not Write-Only)
  assign rdata32   = (sel_r & rcyc_r & (WRITE_ONLY == 0))
                   ? {byte3[word2_r[1:0]], byte2[word2_r[1:0]],
                      byte1[word2_r[1:0]], byte0[word2_r[1:0]]}
                   : 32'h00000000;

endmodule

// include SecWorks IP but fix up default_nettype issues that breaks elsewhere

`include "aes_core.v"
`default_nettype wire
`include "aes_encipher_block.v"
`default_nettype wire
`include "aes_decipher_block.v"
`default_nettype wire
`include "aes_key_mem.v"
`default_nettype wire
`include "aes_sbox.v"
`default_nettype wire
`include "aes_inv_sbox.v"
`default_nettype wire