hw/ip/hmac/rtl/hmac.sv Cov: 99%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // HMAC-SHA256
   6: 
   7: module hmac
   8:   import prim_pkg::*;
   9:   import hmac_pkg::*;
  10:   import hmac_reg_pkg::*;
  11: (
  12:   input clk_i,
  13:   input rst_ni,
  14: 
  15:   input  tlul_pkg::tl_h2d_t tl_i,
  16:   output tlul_pkg::tl_d2h_t tl_o,
  17: 
  18:   output logic intr_hmac_done_o,
  19:   output logic intr_fifo_full_o,
  20:   output logic intr_hmac_err_o,
  21: 
  22:   // alerts
  23:   input  alert_rx_t [NumAlerts-1:0] alert_rx_i,
  24:   output alert_tx_t [NumAlerts-1:0] alert_tx_o
  25: );
  26: 
  27: 
  28:   /////////////////////////
  29:   // Signal declarations //
  30:   /////////////////////////
  31:   hmac_reg2hw_t reg2hw;
  32:   hmac_hw2reg_t hw2reg;
  33: 
  34:   tlul_pkg::tl_h2d_t  tl_win_h2d[1];
  35:   tlul_pkg::tl_d2h_t  tl_win_d2h[1];
  36: 
  37:   logic [255:0] secret_key;
  38: 
  39:   logic        wipe_secret;
  40:   logic [31:0] wipe_v;
  41: 
  42:   logic        fifo_rvalid;
  43:   logic        fifo_rready;
  44:   sha_fifo_t   fifo_rdata;
  45: 
  46:   logic        fifo_wvalid, fifo_wready;
  47:   sha_fifo_t   fifo_wdata;
  48:   logic        fifo_full;
  49:   logic        fifo_empty;
  50:   logic [4:0]  fifo_depth;
  51: 
  52:   logic        msg_fifo_req;
  53:   logic        msg_fifo_gnt;
  54:   logic        msg_fifo_we;
  55:   logic [8:0]  msg_fifo_addr;   // NOT_READ
  56:   logic [31:0] msg_fifo_wdata;
  57:   logic [31:0] msg_fifo_wmask;
  58:   logic [31:0] msg_fifo_rdata;
  59:   logic        msg_fifo_rvalid;
  60:   logic [1:0]  msg_fifo_rerror;
  61:   logic [31:0] msg_fifo_wdata_endian;
  62:   logic [31:0] msg_fifo_wmask_endian;
  63: 
  64:   logic        packer_ready;
  65:   logic        packer_flush_done;
  66: 
  67:   logic        reg_fifo_wvalid;
  68:   sha_word_t   reg_fifo_wdata;
  69:   sha_word_t   reg_fifo_wmask;
  70:   logic        hmac_fifo_wsel;
  71:   logic        hmac_fifo_wvalid;
  72:   logic [2:0]  hmac_fifo_wdata_sel;
  73: 
  74:   logic        shaf_rvalid;
  75:   sha_fifo_t   shaf_rdata;
  76:   logic        shaf_rready;
  77: 
  78:   logic        sha_en;
  79:   logic        hmac_en;
  80:   logic        endian_swap;
  81:   logic        digest_swap;
  82: 
  83:   logic        reg_hash_start;
  84:   logic        sha_hash_start;
  85:   logic        hash_start;      // Valid hash_start_signal
  86:   logic        reg_hash_process;
  87:   logic        sha_hash_process;
  88: 
  89:   logic        reg_hash_done;
  90:   logic        sha_hash_done;
  91: 
  92:   logic [63:0] message_length;
  93:   logic [63:0] sha_message_length;
  94: 
  95:   err_code_e   err_code;
  96:   logic        err_valid;
  97: 
  98:   sha_word_t [7:0] digest;
  99: 
 100:   hmac_reg2hw_cfg_reg_t cfg_reg;
 101:   logic                 cfg_block;  // Prevent changing config
 102: 
 103:   ///////////////////////
 104:   // Connect registers //
 105:   ///////////////////////
 106:   assign hw2reg.status.fifo_full.d  = fifo_full;
 107:   assign hw2reg.status.fifo_empty.d = fifo_empty;
 108:   assign hw2reg.status.fifo_depth.d = fifo_depth;
 109: 
 110:   // secret key
 111:   assign wipe_secret = reg2hw.wipe_secret.qe;
 112:   assign wipe_v      = reg2hw.wipe_secret.q;
 113: 
 114:   always_ff @(posedge clk_i or negedge rst_ni) begin
 115:     if (!rst_ni) begin
 116:       secret_key <= '0;
 117:     end else if (wipe_secret) begin
 118:       secret_key <= secret_key ^ {8{wipe_v}};
 119:     end else if (!cfg_block) begin
 120:       // Allow updating secret key only when the engine is in Idle.
 121:       for (int i = 0; i < 8; i++) begin
 122:         if (reg2hw.key[7-i].qe) begin
 123:           secret_key[32*i+:32] <= reg2hw.key[7-i].q;
 124:         end
 125:       end
 126:     end
 127:   end
 128: 
 129:   for (genvar i = 0; i < 8; i++) begin : gen_key_digest
 130:     assign hw2reg.key[7-i].d      = '0;
 131:     // digest
 132:     assign hw2reg.digest[i].d = conv_endian(digest[i], digest_swap);
 133:   end
 134: 
 135:   logic [3:0] unused_cfg_qe;
 136: 
 137:   assign unused_cfg_qe = {cfg_reg.sha_en.qe,      cfg_reg.hmac_en.qe,
 138:                           cfg_reg.endian_swap.qe, cfg_reg.digest_swap.qe};
 139: 
 140:   assign sha_en      = cfg_reg.sha_en.q;
 141:   assign hmac_en     = cfg_reg.hmac_en.q;
 142:   assign endian_swap = cfg_reg.endian_swap.q;
 143:   assign digest_swap = cfg_reg.digest_swap.q;
 144:   assign hw2reg.cfg.hmac_en.d     = cfg_reg.hmac_en.q;
 145:   assign hw2reg.cfg.sha_en.d      = cfg_reg.sha_en.q;
 146:   assign hw2reg.cfg.endian_swap.d = cfg_reg.endian_swap.q;
 147:   assign hw2reg.cfg.digest_swap.d = cfg_reg.digest_swap.q;
 148: 
 149:   assign reg_hash_start   = reg2hw.cmd.hash_start.qe   & reg2hw.cmd.hash_start.q;
 150:   assign reg_hash_process = reg2hw.cmd.hash_process.qe & reg2hw.cmd.hash_process.q;
 151: 
 152:   // Error code register
 153:   assign hw2reg.err_code.de = err_valid;
 154:   assign hw2reg.err_code.d  = err_code;
 155: 
 156:   /////////////////////
 157:   // Control signals //
 158:   /////////////////////
 159:   assign hash_start = reg_hash_start & sha_en;
 160: 
 161:   always_ff @(posedge clk_i or negedge rst_ni) begin
 162:     if (!rst_ni) begin
 163:       cfg_block <= '0;
 164:     end else if (hash_start) begin
 165:       cfg_block <= 1'b 1;
 166:     end else if (reg_hash_done) begin
 167:       cfg_block <= 1'b 0;
 168:     end
 169:   end
 170:   // Hold the configuration during the process
 171:   always_ff @(posedge clk_i or negedge rst_ni) begin
 172:     if (!rst_ni) begin
 173:       cfg_reg <= '{endian_swap: '{q: 1'b1, qe: 1'b0}, default:'0};
 174:     end else if (!cfg_block && reg2hw.cfg.hmac_en.qe) begin
 175:       cfg_reg <= reg2hw.cfg ;
 176:     end
 177:   end
 178:   ////////////////
 179:   // Interrupts //
 180:   ////////////////
 181:   logic fifo_full_q;
 182:   always_ff @(posedge clk_i or negedge rst_ni) begin
 183:     if (!rst_ni) fifo_full_q <= 1'b0;
 184:     else fifo_full_q <= fifo_full;
 185:   end
 186: 
 187:   logic fifo_full_event;
 188:   assign fifo_full_event = fifo_full & !fifo_full_q;
 189: 
 190:   logic [2:0] event_intr;
 191:   assign event_intr = {err_valid, fifo_full_event, reg_hash_done};
 192: 
 193:   // instantiate interrupt hardware primitive
 194:   prim_intr_hw #(.Width(1)) intr_hw_hmac_done (
 195:     .event_intr_i           (event_intr[0]),
 196:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.hmac_done.q),
 197:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.hmac_done.q),
 198:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.hmac_done.qe),
 199:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.hmac_done.q),
 200:     .hw2reg_intr_state_de_o (hw2reg.intr_state.hmac_done.de),
 201:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.hmac_done.d),
 202:     .intr_o                 (intr_hmac_done_o)
 203:   );
 204:   prim_intr_hw #(.Width(1)) intr_hw_fifo_full (
 205:     .event_intr_i           (event_intr[1]),
 206:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.fifo_full.q),
 207:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.fifo_full.q),
 208:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.fifo_full.qe),
 209:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.fifo_full.q),
 210:     .hw2reg_intr_state_de_o (hw2reg.intr_state.fifo_full.de),
 211:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.fifo_full.d),
 212:     .intr_o                 (intr_fifo_full_o)
 213:   );
 214:   prim_intr_hw #(.Width(1)) intr_hw_hmac_err (
 215:     .event_intr_i           (event_intr[2]),
 216:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.hmac_err.q),
 217:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.hmac_err.q),
 218:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.hmac_err.qe),
 219:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.hmac_err.q),
 220:     .hw2reg_intr_state_de_o (hw2reg.intr_state.hmac_err.de),
 221:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.hmac_err.d),
 222:     .intr_o                 (intr_hmac_err_o)
 223:   );
 224: 
 225:   ///////////////
 226:   // Instances //
 227:   ///////////////
 228: 
 229:   assign msg_fifo_rvalid = msg_fifo_req & ~msg_fifo_we;
 230:   assign msg_fifo_rdata  = '1;  // Return all F
 231:   assign msg_fifo_rerror = '1;  // Return error for read access
 232:   assign msg_fifo_gnt    = msg_fifo_req & ~hmac_fifo_wsel & packer_ready;
 233: 
 234:   // FIFO control
 235:   sha_fifo_t reg_fifo_wentry;
 236:   assign reg_fifo_wentry.data = conv_endian(reg_fifo_wdata, 1'b1); // always convert
 237:   assign reg_fifo_wentry.mask = {reg_fifo_wmask[0],  reg_fifo_wmask[8],
 238:                                  reg_fifo_wmask[16], reg_fifo_wmask[24]};
 239:   assign fifo_full   = ~fifo_wready;
 240:   assign fifo_empty  = ~fifo_rvalid;
 241:   assign fifo_wvalid = (hmac_fifo_wsel && fifo_wready) ? hmac_fifo_wvalid : reg_fifo_wvalid;
 242:   assign fifo_wdata  = (hmac_fifo_wsel) ? '{data: digest[hmac_fifo_wdata_sel], mask: '1}
 243:                                        : reg_fifo_wentry;
 244: 
 245:   prim_fifo_sync #(
 246:     .Width ($bits(sha_fifo_t)),
 247:     .Pass  (1'b0),
 248:     .Depth (MsgFifoDepth)
 249:   ) u_msg_fifo (
 250:     .clk_i,
 251:     .rst_ni,
 252:     .clr_i  (1'b0),
 253: 
 254:     .wvalid (fifo_wvalid & sha_en),
 255:     .wready (fifo_wready),
 256:     .wdata  (fifo_wdata),
 257: 
 258:     .depth  (fifo_depth),
 259: 
 260:     .rvalid (fifo_rvalid),
 261:     .rready (fifo_rready),
 262:     .rdata  (fifo_rdata)
 263:   );
 264: 
 265:   // TL ADAPTER SRAM
 266:   tlul_adapter_sram #(
 267:     .SramAw (9),
 268:     .SramDw (32),
 269:     .Outstanding (1),
 270:     .ByteAccess  (1),
 271:     .ErrOnRead   (1)
 272:   ) u_tlul_adapter (
 273:     .clk_i,
 274:     .rst_ni,
 275:     .tl_i   (tl_win_h2d[0]),
 276:     .tl_o   (tl_win_d2h[0]),
 277: 
 278:     .req_o    (msg_fifo_req   ),
 279:     .gnt_i    (msg_fifo_gnt   ),
 280:     .we_o     (msg_fifo_we    ),
 281:     .addr_o   (msg_fifo_addr  ), // Doesn't care the address other than sub-word
 282:     .wdata_o  (msg_fifo_wdata ),
 283:     .wmask_o  (msg_fifo_wmask ),
 284:     .rdata_i  (msg_fifo_rdata ),
 285:     .rvalid_i (msg_fifo_rvalid),
 286:     .rerror_i (msg_fifo_rerror)
 287:   );
 288: 
 289:   // TL-UL to MSG_FIFO byte write handling
 290:   logic msg_write;
 291: 
 292:   assign msg_write = msg_fifo_req & msg_fifo_we & ~hmac_fifo_wsel;
 293: 
 294:   logic [$clog2(32+1)-1:0] wmask_ones;
 295: 
 296:   always_comb begin
 297:     wmask_ones = '0;
 298:     for (int i = 0 ; i < 32 ; i++) begin
 299:       wmask_ones = wmask_ones + reg_fifo_wmask[i];
 300:     end
 301:   end
 302: 
 303:   // Calculate written message
 304:   always_ff @(posedge clk_i or negedge rst_ni) begin
 305:     if (!rst_ni) begin
 306:       message_length <= '0;
 307:     end else if (hash_start) begin
 308:       message_length <= '0;
 309:     end else if (reg_fifo_wvalid && fifo_wready && !hmac_fifo_wsel) begin
 310:       message_length <= message_length + 64'(wmask_ones);
 311:     end
 312:   end
 313: 
 314:   assign hw2reg.msg_length_upper.de = 1'b1;
 315:   assign hw2reg.msg_length_upper.d = message_length[63:32];
 316:   assign hw2reg.msg_length_lower.de = 1'b1;
 317:   assign hw2reg.msg_length_lower.d = message_length[31:0];
 318: 
 319: 
 320:   // Convert endian here
 321:   //    prim_packer always packs to the right, but SHA engine assumes incoming
 322:   //    to be big-endian, [31:24] comes first. So, the data is reverted after
 323:   //    prim_packer before the message fifo. here to reverse if not big-endian
 324:   //    before pushing to the packer.
 325:   assign msg_fifo_wdata_endian = conv_endian(msg_fifo_wdata, ~endian_swap);
 326:   assign msg_fifo_wmask_endian = conv_endian(msg_fifo_wmask, ~endian_swap);
 327: 
 328:   prim_packer #(
 329:     .InW      (32),
 330:     .OutW     (32)
 331:   ) u_packer (
 332:     .clk_i,
 333:     .rst_ni,
 334: 
 335:     .valid_i      (msg_write & sha_en),
 336:     .data_i       (msg_fifo_wdata_endian),
 337:     .mask_i       (msg_fifo_wmask_endian),
 338:     .ready_o      (packer_ready),
 339: 
 340:     .valid_o      (reg_fifo_wvalid),
 341:     .data_o       (reg_fifo_wdata),
 342:     .mask_o       (reg_fifo_wmask),
 343:     .ready_i      (fifo_wready & ~hmac_fifo_wsel),
 344: 
 345:     .flush_i      (reg_hash_process),
 346:     .flush_done_o (packer_flush_done) // ignore at this moment
 347:   );
 348: 
 349: 
 350:   hmac_core u_hmac (
 351:     .clk_i,
 352:     .rst_ni,
 353: 
 354:     .secret_key,
 355: 
 356:     .wipe_secret,
 357:     .wipe_v,
 358: 
 359:     .hmac_en,
 360: 
 361:     .reg_hash_start   (hash_start),
 362:     .reg_hash_process (packer_flush_done), // Trigger after all msg written
 363:     .hash_done      (reg_hash_done),
 364:     .sha_hash_start,
 365:     .sha_hash_process,
 366:     .sha_hash_done,
 367: 
 368:     .sha_rvalid     (shaf_rvalid),
 369:     .sha_rdata      (shaf_rdata),
 370:     .sha_rready     (shaf_rready),
 371: 
 372:     .fifo_rvalid,
 373:     .fifo_rdata,
 374:     .fifo_rready,
 375: 
 376:     .fifo_wsel      (hmac_fifo_wsel),
 377:     .fifo_wvalid    (hmac_fifo_wvalid),
 378:     .fifo_wdata_sel (hmac_fifo_wdata_sel),
 379:     .fifo_wready,
 380: 
 381:     .message_length,
 382:     .sha_message_length
 383:   );
 384: 
 385:   sha2 u_sha2 (
 386:     .clk_i,
 387:     .rst_ni,
 388: 
 389:     .wipe_secret,
 390:     .wipe_v,
 391: 
 392:     .fifo_rvalid      (shaf_rvalid),
 393:     .fifo_rdata       (shaf_rdata),
 394:     .fifo_rready      (shaf_rready),
 395: 
 396:     .sha_en,
 397:     .hash_start       (sha_hash_start),
 398:     .hash_process     (sha_hash_process),
 399:     .hash_done        (sha_hash_done),
 400: 
 401:     .message_length   (sha_message_length),
 402: 
 403:     .digest
 404:   );
 405: 
 406:   hmac_reg_top u_reg (
 407:     .clk_i,
 408:     .rst_ni,
 409: 
 410:     .tl_i,
 411:     .tl_o,
 412: 
 413:     .tl_win_o   (tl_win_h2d),
 414:     .tl_win_i   (tl_win_d2h),
 415: 
 416:     .reg2hw,
 417:     .hw2reg,
 418: 
 419:     .devmode_i  (1'b1)
 420:   );
 421: 
 422:   /////////////////////////
 423:   // HMAC Error Handling //
 424:   /////////////////////////
 425:   logic msg_push_sha_disabled, hash_start_sha_disabled, update_seckey_inprocess;
 426:   assign msg_push_sha_disabled = msg_write & ~sha_en;
 427:   assign hash_start_sha_disabled = reg_hash_start & ~sha_en;
 428: 
 429:   always_comb begin
 430:     update_seckey_inprocess = 1'b0;
 431:     if (cfg_block) begin
 432:       for (int i = 0 ; i < 8 ; i++) begin
 433:         if (reg2hw.key[i].qe) begin
 434:           update_seckey_inprocess = update_seckey_inprocess | 1'b1;
 435:         end
 436:       end
 437:     end else begin
 438:       update_seckey_inprocess = 1'b0;
 439:     end
 440:   end
 441: 
 442:   // Update ERR_CODE register and interrupt only when no pending interrupt.
 443:   // This ensures only the first event of the series of events can be seen to sw.
 444:   // It is recommended that the software reads ERR_CODE register when interrupt
 445:   // is pending to avoid any race conditions.
 446:   assign err_valid = ~reg2hw.intr_state.hmac_err.q &
 447:                    ( msg_push_sha_disabled | hash_start_sha_disabled
 448:                    | update_seckey_inprocess);
 449: 
 450:   always_comb begin
 451:     err_code = NoError;
 452:     unique case (1'b1)
 453:       msg_push_sha_disabled: begin
 454:         err_code = SwPushMsgWhenShaDisabled;
 455:       end
 456:       hash_start_sha_disabled: begin
 457:         err_code = SwHashStartWhenShaDisabled;
 458:       end
 459: 
 460:       update_seckey_inprocess: begin
 461:         err_code = SwUpdateSecretKeyInProcess;
 462:       end
 463: 
 464:       default: begin
 465:         err_code = NoError;
 466:       end
 467:     endcase
 468:   end
 469: 
 470:   /////////////////////
 471:   // Hardware Alerts //
 472:   /////////////////////
 473: 
 474:   // TODO: add CSR with REGWEN to test alert via SW
 475:   logic [NumAlerts-1:0] alerts;
 476:   assign alerts = {msg_push_sha_disabled};
 477: 
 478:   for (genvar j = 0; j < hmac_pkg::NumAlerts; j++) begin : gen_alert_tx
 479:     prim_alert_sender #(
 480:       .AsyncOn(hmac_pkg::AlertAsyncOn[j])
 481:     ) i_prim_alert_sender (
 482:       .clk_i      ( clk_i         ),
 483:       .rst_ni     ( rst_ni        ),
 484:       .alert_i    ( alerts[j]     ),
 485:       .alert_rx_i ( alert_rx_i[j] ),
 486:       .alert_tx_o ( alert_tx_o[j] )
 487:     );
 488:   end : gen_alert_tx
 489: 
 490:   //////////////////////////////////////////////
 491:   // Assertions, Assumptions, and Coverpoints //
 492:   //////////////////////////////////////////////
 493: 
 494: `ifndef VERILATOR
 495: `ifndef SYNTHESIS
 496:   // HMAC assumes TL-UL mask is byte-aligned.
 497:     property wmask_bytealign_p(wmask_byte, clk, rst_n);
 498:       @(posedge clk) disable iff (rst_n == 0)
 499:         msg_fifo_req & msg_fifo_we |-> wmask_byte inside {'0, '1};
 500:     endproperty
 501: 
 502:     for (genvar i = 0 ; i < 4; i++) begin: gen_assert_wmask_bytealign
 503:       assert property (wmask_bytealign_p(msg_fifo_wmask[8*i+:8], clk_i, rst_ni));
 504:     end
 505: 
 506:   // To pass FPV, this shouldn't add pragma translate_off even these two signals
 507:   // are used in Assertion only
 508:   logic in_process;
 509:   always_ff @(posedge clk_i or negedge rst_ni) begin
 510:     if (!rst_ni)               in_process <= 1'b0;
 511:     else if (reg_hash_process) in_process <= 1'b1;
 512:     else if (reg_hash_done)    in_process <= 1'b0;
 513:   end
 514: 
 515:   logic initiated;
 516:   always_ff @(posedge clk_i or negedge rst_ni) begin
 517:     if (!rst_ni)               initiated <= 1'b0;
 518:     else if (hash_start)       initiated <= 1'b1;
 519:     else if (reg_hash_process) initiated <= 1'b0;
 520:   end
 521: 
 522:   // the host doesn't write data after hash_process until hash_start.
 523:   // Same as "message_length shouldn't be changed between hash_process and done
 524:   `ASSERT(ValidWriteAssert, msg_fifo_req |-> !in_process, clk_i, !rst_ni)
 525: 
 526:   // `hash_process` shall be toggle and paired with `hash_start`.
 527:   `ASSERT(ValidHashStartAssert, hash_start |-> !initiated, clk_i, !rst_ni)
 528:   `ASSERT(ValidHashProcessAssert, reg_hash_process |-> initiated, clk_i, !rst_ni)
 529: 
 530:   // between `hash_done` and `hash_start`, message FIFO should be empty
 531:   `ASSERT(MsgFifoEmptyWhenNoOpAssert,
 532:           !in_process && !initiated |-> $stable(message_length),
 533:           clk_i, !rst_ni)
 534: 
 535:   // hmac_en should be modified only when the logic is Idle
 536:   `ASSERT(ValidHmacEnConditionAssert,
 537:           hmac_en != $past(hmac_en) |-> !in_process && !initiated,
 538:           clk_i, !rst_ni)
 539: 
 540:   // All outputs should be known value after reset
 541:   `ASSERT_KNOWN(IntrHmacDoneOKnown, intr_hmac_done_o, clk_i, !rst_ni)
 542:   `ASSERT_KNOWN(IntrFifoFullOKnown, intr_fifo_full_o, clk_i, !rst_ni)
 543:   `ASSERT_KNOWN(TlODValidKnown, tl_o.d_valid, clk_i, !rst_ni)
 544:   `ASSERT_KNOWN(TlOAReadyKnown, tl_o.a_ready, clk_i, !rst_ni)
 545: 
 546:   // Alert outputs
 547:   `ASSERT_KNOWN(AlertTxOKnown, alert_tx_o, clk_i, !rst_ni)
 548: 
 549: `endif // SYNTHESIS
 550: `endif // VERILATOR
 551: 
 552: endmodule
 553: